diff --git a/Makefile.am b/Makefile.am index 002982d9..f5ba9689 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,9 +19,10 @@ bin_PROGRAMS = xsecurelock xsecurelock_SOURCES = \ auth_child.c auth_child.h \ env_settings.c env_settings.h \ - saver_child.c saver_child.h \ + logging.c logging.h \ mlock_page.h \ main.c \ + saver_child.c saver_child.h \ wm_properties.c wm_properties.h \ xscreensaver_api.c xscreensaver_api.h xsecurelock_CPPFLAGS = \ @@ -69,9 +70,10 @@ endif helpers_PROGRAMS = \ saver_multiplex saver_multiplex_SOURCES = \ - helpers/saver_multiplex.c \ env_settings.c env_settings.h \ helpers/monitors.c helpers/monitors.h \ + helpers/saver_multiplex.c \ + logging.c logging.h \ saver_child.c saver_child.h \ wm_properties.c wm_properties.h \ xscreensaver_api.c xscreensaver_api.h @@ -85,9 +87,10 @@ if HAVE_PAM helpers_PROGRAMS += \ auth_pam_x11 auth_pam_x11_SOURCES = \ - helpers/auth_pam_x11.c \ env_settings.c env_settings.h \ + helpers/auth_pam_x11.c \ helpers/monitors.c helpers/monitors.h \ + logging.c logging.h \ mlock_page.h \ xscreensaver_api.c xscreensaver_api.h auth_pam_x11_CPPFLAGS = \ diff --git a/auth_child.c b/auth_child.c index 426af388..e06b0b19 100644 --- a/auth_child.c +++ b/auth_child.c @@ -18,14 +18,14 @@ limitations under the License. #include // for ECHILD, EINTR, errno #include // for kill, SIGTERM -#include // for perror, fprintf, stderr -#include // for NULL, exit, EXIT_FAILURE, etc +#include // for NULL, exit, EXIT_FAILURE, EXIT_SUCCESS #include // for strlen -#include // for waitpid, WEXITSTATUS, etc -#include // for close, pid_t, ssize_t, dup2, etc +#include // for WIFEXITED, WIFSIGNALED, waitpid, WEXIT... +#include // for close, pid_t, ssize_t, dup2, execl, fork -#include "env_settings.h" -#include "xscreensaver_api.h" +#include "env_settings.h" // for GetIntSetting +#include "logging.h" // for LogErrno, Log +#include "xscreensaver_api.h" // for ExportWindowID //! The PID of a currently running saver child, or 0 if none is running. static pid_t auth_child_pid = 0; @@ -106,7 +106,7 @@ int WatchAuthChild(Display *dpy, Window w, const char *executable, break; default: // Assume the child still lives. Shouldn't ever happen. - perror("waitpid"); + LogErrno("waitpid"); break; } } else if (pid == auth_child_pid) { @@ -129,13 +129,12 @@ int WatchAuthChild(Display *dpy, Window w, const char *executable, // Only report signals; "normal" exit is not worth logging as it usually // means authentication failure anyway. if (WIFSIGNALED(status)) { - fprintf(stderr, "Auth child killed by signal %d.\n", - WTERMSIG(status)); + Log("Auth child killed by signal %d", WTERMSIG(status)); } } // Otherwise, it was suspended or whatever. We need to keep waiting. } else if (pid != 0) { - fprintf(stderr, "Unexpectedly woke up for PID %d.\n", (int)pid); + Log("Unexpectedly woke up for PID %d", (int)pid); } // Otherwise, we're still alive. } @@ -144,11 +143,11 @@ int WatchAuthChild(Display *dpy, Window w, const char *executable, // Start auth child. int pc[2]; if (pipe(pc)) { - perror("pipe"); + LogErrno("pipe"); } else { pid_t pid = fork(); if (pid == -1) { - perror("fork"); + LogErrno("fork"); } else if (pid == 0) { // Child process. setsid(); @@ -157,7 +156,7 @@ int WatchAuthChild(Display *dpy, Window w, const char *executable, close(pc[0]); close(pc[1]); execl(executable, executable, NULL); // Flawfinder: ignore - perror("execl"); + LogErrno("execl"); exit(EXIT_FAILURE); } else { // Parent process after successful fork. @@ -184,12 +183,12 @@ int WatchAuthChild(Display *dpy, Window w, const char *executable, ssize_t to_write = (ssize_t)strlen(stdinbuf); // Flawfinder: ignore ssize_t written = write(auth_child_fd, stdinbuf, to_write); if (written < 0) { - perror("Failed to send all data to the auth child"); + LogErrno("Failed to send all data to the auth child"); } else if (written != to_write) { - fprintf(stderr, "Failed to send all data to the auth child.\n"); + Log("Failed to send all data to the auth child"); } } else { - fprintf(stderr, "No auth child. Can't send key events...\n"); + Log("No auth child. Can't send key events"); } } diff --git a/env_settings.c b/env_settings.c index fabdb7e9..5f4df4ee 100644 --- a/env_settings.c +++ b/env_settings.c @@ -20,6 +20,8 @@ limitations under the License. #include // for fprintf, NULL, stderr #include // for getenv, strtol, strtoull +#include "logging.h" + unsigned long long GetUnsignedLongLongSetting(const char* name, unsigned long long def) { const char* value = getenv(name); // Flawfinder: ignore @@ -30,11 +32,11 @@ unsigned long long GetUnsignedLongLongSetting(const char* name, errno = 0; unsigned long long number = strtoull(value, &endptr, 0); if (errno == ERANGE) { - fprintf(stderr, "Ignoring out-of-range value of %s: %s.", name, value); + Log("Ignoring out-of-range value of %s: %s", name, value); return def; } if ((endptr != NULL && *endptr != 0)) { - fprintf(stderr, "Ignoring non-numeric value of %s: %s.", name, value); + Log("Ignoring non-numeric value of %s: %s", name, value); return def; } return number; @@ -49,11 +51,11 @@ long GetLongSetting(const char* name, long def) { errno = 0; long number = strtol(value, &endptr, 0); if (errno == ERANGE) { - fprintf(stderr, "Ignoring out-of-range value of %s: %s.", name, value); + Log("Ignoring out-of-range value of %s: %s", name, value); return def; } if ((endptr != NULL && *endptr != 0)) { - fprintf(stderr, "Ignoring non-numeric value of %s: %s.", name, value); + Log("Ignoring non-numeric value of %s: %s", name, value); return def; } return number; @@ -63,7 +65,7 @@ int GetIntSetting(const char* name, int def) { long lnumber = GetLongSetting(name, def); int number = (int)lnumber; if (lnumber != (long)number) { - fprintf(stderr, "Ignoring out-of-range value of %s: %d.", name, number); + Log("Ignoring out-of-range value of %s: %d", name, number); return def; } return number; diff --git a/helpers/auth_pam_x11.c b/helpers/auth_pam_x11.c index fbc158ef..6696b8cd 100644 --- a/helpers/auth_pam_x11.c +++ b/helpers/auth_pam_x11.c @@ -22,7 +22,7 @@ limitations under the License. #include // for getpwuid, passwd #include // for PAM_SUCCESS, pam_strerror, pam_re... #include // for pam_end, pam_start, pam_acct_mgmt -#include // for fprintf, stderr, perror, NULL +#include // for fprintf, stderr, LogErrno, NULL #include // for mblen, exit, free, calloc, getenv #include // for memcpy, strlen, memset #include // for timeval, select, FD_SET, FD_ZERO @@ -34,6 +34,7 @@ limitations under the License. #endif #include "../env_settings.h" // for GetStringSetting +#include "../logging.h" // for Log, LogErrno #include "../mlock_page.h" // for MLOCK_PAGE #include "../xscreensaver_api.h" // for ReadWindowID #include "monitors.h" // for Monitor, GetMonitors, IsMonitorCh... @@ -94,19 +95,19 @@ const char *get_indicators() { xkb = XkbGetMap(display, 0, XkbUseCoreKbd); if (XkbGetNames(display, XkbIndicatorNamesMask | XkbGroupNamesMask, xkb) != Success) { - fprintf(stderr, "XkbGetNames failed\n"); + Log("XkbGetNames failed"); XkbFreeClientMap(xkb, 0, True); return ""; } XkbStateRec state; if (XkbGetState(display, XkbUseCoreKbd, &state) != Success) { - fprintf(stderr, "XkbGetState failed\n"); + Log("XkbGetState failed"); XkbFreeClientMap(xkb, 0, True); return ""; } unsigned int istate; if (XkbGetIndicatorState(display, XkbUseCoreKbd, &istate) != Success) { - fprintf(stderr, "XkbGetIndicatorState failed\n"); + Log("XkbGetIndicatorState failed"); XkbFreeClientMap(xkb, 0, True); return ""; } @@ -116,7 +117,7 @@ const char *get_indicators() { const char *word = "Keyboard: "; size_t n = strlen(word); // Flawfinder: ignore if (n >= sizeof(buf) - (p - buf)) { - fprintf(stderr, "Not enough space to store intro '%s'.\n", word); + Log("Not enough space to store intro '%s'", word); return ""; } memcpy(p, word, n); // Flawfinder: ignore @@ -125,7 +126,7 @@ const char *get_indicators() { word = XGetAtomName(display, xkb->names->groups[state.group]); n = strlen(word); // Flawfinder: ignore if (n >= sizeof(buf) - (p - buf)) { - fprintf(stderr, "Not enough space to store group name '%s'.\n", word); + Log("Not enough space to store group name '%s'", word); return ""; } memcpy(p, word, n); // Flawfinder: ignore @@ -143,10 +144,10 @@ const char *get_indicators() { const char *word = XGetAtomName(display, namea); size_t n = strlen(word); // Flawfinder: ignore if (n + 2 >= sizeof(buf) - (p - buf)) { - fprintf(stderr, "Not enough space to store modifier name '%s'.\n", word); + Log("Not enough space to store modifier name '%s'", word); continue; } - memcpy(p, ", ", 2); // Flawfinder: ignore + memcpy(p, ", ", 2); // Flawfinder: ignore memcpy(p + 2, word, n); // Flawfinder: ignore p += n + 2; } @@ -318,7 +319,7 @@ int prompt(const char *msg, char **response, int echo) { int blinks = 0; if (!echo && MLOCK_PAGE(&priv, sizeof(priv)) < 0) { - perror("mlock"); + LogErrno("mlock"); // We continue anyway, as the user being unable to unlock the screen is // worse. But let's alert the user. alert("Password will not be stored securely.", 1); @@ -391,7 +392,7 @@ int prompt(const char *msg, char **response, int echo) { FD_SET(0, &set); int nfds = select(1, &set, NULL, NULL, &timeout); if (nfds < 0) { - perror("select"); + LogErrno("select"); done = 1; break; } @@ -409,7 +410,7 @@ int prompt(const char *msg, char **response, int echo) { ssize_t nread = read(0, &priv.inputbuf, 1); // Flawfinder: ignore if (nread <= 0) { - fprintf(stderr, "EOF on password input - bailing out.\n"); + Log("EOF on password input - bailing out"); done = 1; break; } @@ -450,7 +451,7 @@ int prompt(const char *msg, char **response, int echo) { case '\n': *response = malloc(priv.pwlen + 1); if (!echo && MLOCK_PAGE(*response, priv.pwlen + 1) < 0) { - perror("mlock"); + LogErrno("mlock"); // We continue anyway, as the user being unable to unlock the screen // is worse. But let's alert the user of this. alert("Password has not been stored securely.", 1); @@ -474,7 +475,7 @@ int prompt(const char *msg, char **response, int echo) { PARANOID_PASSWORD_LENGTH; #endif } else { - fprintf(stderr, "Password entered is too long - bailing out.\n"); + Log("Password entered is too long - bailing out"); done = 1; break; } @@ -495,7 +496,7 @@ int prompt(const char *msg, char **response, int echo) { memset(&priv, 0, sizeof(priv)); if (!done) { - fprintf(stderr, "Unreachable code - the loop above must set done.\n"); + Log("Unreachable code - the loop above must set done"); } return status; } @@ -539,11 +540,10 @@ int converse(int num_msg, const struct pam_message **msg, (void)appdata_ptr; if (conv_error) { - fprintf(stderr, - "converse() got called again with %d messages (first: %s) after " - "having failed before - this is very likely a bug in the PAM " - "module having made the call. Bailing out.\n", - num_msg, num_msg <= 0 ? "(none)" : msg[0]->msg); + Log("converse() got called again with %d messages (first: %s) after " + "having failed before - this is very likely a bug in the PAM " + "module having made the call. Bailing out", + num_msg, num_msg <= 0 ? "(none)" : msg[0]->msg); exit(1); } @@ -610,32 +610,32 @@ int authenticate(const char *username, const char *hostname, GetStringSetting("XSECURELOCK_PAM_SERVICE", PAM_SERVICE_NAME); int status = pam_start(service_name, username, conv, pam); if (status != PAM_SUCCESS) { - fprintf(stderr, "pam_start: %d\n", - status); // Or can one call pam_strerror on a NULL handle? + Log("pam_start: %d", + status); // Or can one call pam_strerror on a NULL handle? return status; } status = pam_set_item(*pam, PAM_RHOST, hostname); if (status != PAM_SUCCESS) { - fprintf(stderr, "pam_set_item: %s\n", pam_strerror(*pam, status)); + Log("pam_set_item: %s", pam_strerror(*pam, status)); return status; } status = pam_set_item(*pam, PAM_RUSER, username); if (status != PAM_SUCCESS) { - fprintf(stderr, "pam_set_item: %s\n", pam_strerror(*pam, status)); + Log("pam_set_item: %s", pam_strerror(*pam, status)); return status; } const char *display = getenv("DISPLAY"); // Flawfinder: ignore status = pam_set_item(*pam, PAM_TTY, display); if (status != PAM_SUCCESS) { - fprintf(stderr, "pam_set_item: %s\n", pam_strerror(*pam, status)); + Log("pam_set_item: %s", pam_strerror(*pam, status)); return status; } status = call_pam_with_retries(pam_authenticate, *pam, 0); if (status != PAM_SUCCESS) { if (!conv_error) { - fprintf(stderr, "pam_authenticate: %s\n", pam_strerror(*pam, status)); + Log("pam_authenticate: %s", pam_strerror(*pam, status)); } return status; } @@ -647,7 +647,7 @@ int authenticate(const char *username, const char *hostname, #ifdef PAM_CHECK_ACCOUNT_TYPE if (status2 != PAM_SUCCESS) { if (!conv_error) { - fprintf(stderr, "pam_chauthtok: %s\n", pam_strerror(*pam, status2)); + Log("pam_chauthtok: %s", pam_strerror(*pam, status2)); } return status2; } @@ -661,7 +661,7 @@ int authenticate(const char *username, const char *hostname, // If this one is true, it must be coming from pam_acct_mgmt, as // pam_chauthtok's result already has been checked against PAM_SUCCESS. if (!conv_error) { - fprintf(stderr, "pam_acct_mgmt: %s\n", pam_strerror(*pam, status2)); + Log("pam_acct_mgmt: %s", pam_strerror(*pam, status2)); } return status2; } @@ -685,13 +685,13 @@ int main() { #endif if ((display = XOpenDisplay(NULL)) == NULL) { - fprintf(stderr, "could not connect to $DISPLAY\n"); + Log("Could not connect to $DISPLAY"); return 1; } char hostname[256]; // Flawfinder: ignore if (gethostname(hostname, sizeof(hostname))) { - perror("gethostname"); + LogErrno("gethostname"); return 1; } hostname[sizeof(hostname) - 1] = 0; @@ -705,19 +705,19 @@ int main() { } pwd_buf = malloc((size_t)pwd_bufsize); if (!pwd_buf) { - perror("malloc(pwd_bufsize)"); + LogErrno("malloc(pwd_bufsize)"); return 1; } getpwuid_r(getuid(), &pwd_storage, pwd_buf, (size_t)pwd_bufsize, &pwd); if (!pwd) { - perror("getpwuid_r"); + LogErrno("getpwuid_r"); free(pwd_buf); return 1; } window = ReadWindowID(); if (window == None) { - fprintf(stderr, "Invalid/no window ID in XSCREENSAVER_WINDOW.\n"); + Log("Invalid/no window ID in XSCREENSAVER_WINDOW"); free(pwd_buf); return 1; } @@ -730,17 +730,16 @@ int main() { if (font_name[0] != 0) { font = XLoadQueryFont(display, font_name); if (font == NULL) { - fprintf(stderr, - "could not load the specified font %s - trying to fall back to " - "fixed\n", - font_name); + Log("Could not load the specified font %s - trying to fall back to " + "fixed", + font_name); } } if (font == NULL) { font = XLoadQueryFont(display, "fixed"); } if (font == NULL) { - fprintf(stderr, "could not load a mind-bogglingly stupid font\n"); + Log("Could not load a mind-bogglingly stupid font"); exit(1); } @@ -772,7 +771,7 @@ int main() { return 1; } if (status2 != PAM_SUCCESS) { - fprintf(stderr, "pam_end: %s\n", pam_strerror(pam, status2)); + Log("pam_end: %s", pam_strerror(pam, status2)); return 1; } diff --git a/helpers/auth_pamtester.in b/helpers/auth_pamtester.in index 65733415..41bd1284 100644 --- a/helpers/auth_pamtester.in +++ b/helpers/auth_pamtester.in @@ -18,4 +18,4 @@ echo "Enter password:" |\ display -window "$XSCREENSAVER_WINDOW" TEXT:- exec >/dev/null 2>&1 -exec pamtester @pam_service_name@ "$USER" authenticate +exec @with_pamtester@ @pam_service_name@ "$USER" authenticate diff --git a/helpers/monitors.c b/helpers/monitors.c index ae6cf02b..aa8a0ca9 100644 --- a/helpers/monitors.c +++ b/helpers/monitors.c @@ -17,19 +17,19 @@ limitations under the License. #include "monitors.h" #include // for XWindowAttributes, Display, XGetW... -#include // for fprintf, stderr #include // for qsort #include // for memcmp, memset #ifdef HAVE_XRANDR -#include // for XRRCrtcInfo, XRROutputInfo, XRRSc... -#include // for RRNotify, RRCrtcChangeNotifyMask +#include // for XRRMonitorInfo, XRRCrtcInfo, XRRO... +#include // for RANDR_MAJOR, RRNotify, RANDR_MINOR #if RANDR_MAJOR > 1 || (RANDR_MAJOR == 1 && RANDR_MINOR >= 5) #define HAVE_XRANDR15 #endif #endif #include "../env_settings.h" // for GetIntSetting +#include "../logging.h" // for Log #ifdef HAVE_XRANDR static Display* initialized_for = NULL; @@ -94,19 +94,19 @@ static int IntervalsOverlap(int astart, int asize, int bstart, int bsize) { static void AddMonitor(Monitor* out_monitors, size_t* num_monitors, size_t max_monitors, int x, int y, int w, int h) { #ifdef DEBUG_EVENTS - fprintf(stderr, "try %d %d %d %d\n", x, y, w, h); + Log("AddMonitor %d %d %d %d", x, y, w, h); #endif // Too many monitors? Stop collecting them. if (*num_monitors >= max_monitors) { #ifdef DEBUG_EVENTS - fprintf(stderr, "skip (too many)\n"); + Log("Skip (too many)"); #endif return; } // Skip empty "monitors". if (w <= 0 || h <= 0) { #ifdef DEBUG_EVENTS - fprintf(stderr, "skip (zero)\n"); + Log("Skip (zero)"); #endif return; } @@ -116,13 +116,13 @@ static void AddMonitor(Monitor* out_monitors, size_t* num_monitors, if (IntervalsOverlap(x, w, out_monitors[i].x, out_monitors[i].width) && IntervalsOverlap(y, h, out_monitors[i].y, out_monitors[i].height)) { #ifdef DEBUG_EVENTS - fprintf(stderr, "skip (overlap with %d)\n", (int)i); + Log("Skip (overlap with %d)", (int)i); #endif return; } } #ifdef DEBUG_EVENTS - fprintf(stderr, "monitor %d = %d %d %d %d\n", (int)*num_monitors, x, y, w, h); + Log("Monitor %d = %d %d %d %d", (int)*num_monitors, x, y, w, h); #endif out_monitors[*num_monitors].x = x; out_monitors[*num_monitors].y = y; @@ -209,7 +209,7 @@ static int GetMonitorsXRandR(Display* dpy, Window w, Window child; if (!XTranslateCoordinates(dpy, w, DefaultRootWindow(dpy), xwa->x, xwa->y, &wx, &wy, &child)) { - fprintf(stderr, "XTranslateCoordinates failed.\n"); + Log("XTranslateCoordinates failed"); wx = xwa->x; wy = xwa->y; } @@ -264,7 +264,7 @@ size_t GetMonitors(Display* dpy, Window w, Monitor* out_monitors, } #endif GetMonitorsGuess(&xwa, out_monitors, &num_monitors, max_monitors); - } while(0); + } while (0); // Sort the monitors in some deterministic order. qsort(out_monitors, num_monitors, sizeof(*out_monitors), CompareMonitors); diff --git a/helpers/saver_multiplex.c b/helpers/saver_multiplex.c index fada249c..be52a4d4 100644 --- a/helpers/saver_multiplex.c +++ b/helpers/saver_multiplex.c @@ -24,6 +24,7 @@ limitations under the License. #include // for sleep #include "../env_settings.h" // for GetStringSetting +#include "../logging.h" // for Log, LogErrno #include "../saver_child.h" // for MAX_SAVERS #include "../wm_properties.h" // for SetWMProperties #include "../xscreensaver_api.h" // for ReadWindowID @@ -92,7 +93,7 @@ static void KillSavers(void) { */ int main(int argc, char** argv) { if (GetIntSetting("XSECURELOCK_INSIDE_SAVER_MULTIPLEX", 0)) { - fprintf(stderr, "starting saver_multiplex inside saver_multiplex?!?\n"); + Log("Starting saver_multiplex inside saver_multiplex?!?"); // If we die, the parent process will revive us, so let's sleep a while to // conserve battery and avoid log spam in this case. sleep(60); @@ -101,14 +102,14 @@ int main(int argc, char** argv) { setenv("XSECURELOCK_INSIDE_SAVER_MULTIPLEX", "1", 1); if ((display = XOpenDisplay(NULL)) == NULL) { - fprintf(stderr, "could not connect to $DISPLAY\n"); + Log("Could not connect to $DISPLAY"); return 1; } int x11_fd = ConnectionNumber(display); Window parent = ReadWindowID(); if (parent == None) { - fprintf(stderr, "Invalid/no parent ID in XSCREENSAVER_WINDOW.\n"); + Log("Invalid/no parent ID in XSCREENSAVER_WINDOW"); return 1; } @@ -135,14 +136,14 @@ int main(int argc, char** argv) { sa.sa_flags = 0; sa.sa_handler = handle_sigterm; if (sigaction(SIGTERM, &sa, NULL) != 0) { - perror("sigaction(SIGTERM)"); + LogErrno("sigaction(SIGTERM)"); } sa.sa_handler = handle_sigchld; if (sigaction(SIGCHLD, &sa, NULL) != 0) { - perror("sigaction(SIGCHLD)"); + LogErrno("sigaction(SIGCHLD)"); } } else { - perror("sigprocmask failed; not installing signal handlers"); + LogErrno("sigprocmask failed; not installing signal handlers"); } for (;;) { fd_set in_fds; diff --git a/helpers/saver_xscreensaver.in b/helpers/saver_xscreensaver.in index ab072b0a..503a47e6 100755 --- a/helpers/saver_xscreensaver.in +++ b/helpers/saver_xscreensaver.in @@ -92,7 +92,7 @@ while :; do $saver fi sleep 2 - echo >&2 "Screen saver failed: $saver. Trying another one..." + echo >&2 "xsecurelock: Screen saver failed: $saver. Trying another one..." selected=$((selected + 1)) mode=random done & diff --git a/logging.c b/logging.c new file mode 100644 index 00000000..097e5d57 --- /dev/null +++ b/logging.c @@ -0,0 +1,27 @@ +#include "logging.h" + +#include // for errno +#include // for va_end, va_list, va_start +#include // for fputs, stderr, vfprintf, perror, NULL + +void Log(const char *format, ...) { + va_list args; + va_start(args, format); + fputs("xsecurelock: ", stderr); + vfprintf(stderr, format, args); // Flawfinder: ignore + fputs(".\n", stderr); + va_end(args); +} + +void LogErrno(const char *format, ...) { + int errno_save = errno; + va_list args; + va_start(args, format); + fputs("xsecurelock: ", stderr); + vfprintf(stderr, format, args); // Flawfinder: ignore + fputs(": ", stderr); + errno = errno_save; + perror(NULL); + va_end(args); + errno = errno_save; +} diff --git a/logging.h b/logging.h new file mode 100644 index 00000000..06515dae --- /dev/null +++ b/logging.h @@ -0,0 +1,39 @@ +/* +Copyright 2018 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef LOGGING_H +#define LOGGING_H + +/*! \brief Prints the given string to the error log (stderr). + * + * For a format expanding to "Foo", this will log "xsecurelock: Foo.". + * + * \param format A printf format string, followed by its arguments. + */ +void Log(const char *format, ...) + __attribute__((format(printf, 1, 2))); // Flawfinder: ignore + +/*! \brief Prints the given string to the error log (stderr). + * + * For a format expanding to "Foo", this may log "xsecurelock: Foo: No such + * file or directory". The value of errno is preserved by this function. + * + * \param format A printf format string, followed by its arguments. + */ +void LogErrno(const char *format, ...) + __attribute__((format(printf, 1, 2))); // Flawfinder: ignore + +#endif diff --git a/main.c b/main.c index 6f3a0016..d5de8dc4 100644 --- a/main.c +++ b/main.c @@ -22,16 +22,16 @@ limitations under the License. */ #include // for Window, GrabModeAsync, Curren... -#include // for XA_ATOM +#include // for XA_CARDINAL, XA_ATOM #include // for XEvent, False, XSelectInput #include // for XLookupString #include // for ECHILD, EINTR, errno #include // for NULL, setlocale, LC_CTYPE #include // for sigaction, sigemptyset, SIGPIPE -#include // for fprintf, stderr, perror, printf +#include // for printf, size_t #include // for EXIT_SUCCESS, exit, EXIT_FAILURE #include // for __s1_len, __s2_len, memset -#include // for timeval, select, FD_SET, FD_ZERO +#include // for timeval, fd_set, select, FD_SET #include // for WEXITSTATUS, waitpid, WIFEXITED #include // for nanosleep, timespec #include // for access, pid_t, X_OK, chdir @@ -49,6 +49,7 @@ limitations under the License. #include "auth_child.h" // for WantAuthChild, WatchAuthChild #include "env_settings.h" // for GetIntSetting, GetStringSetting +#include "logging.h" // for Log, LogErrno #include "mlock_page.h" // for MLOCK_PAGE #include "saver_child.h" // for WatchSaverChild #include "wm_properties.h" // for SetWMProperties @@ -178,7 +179,7 @@ int IgnoreErrorsHandler(Display *display, XErrorEvent *error) { char buf[128]; // Flawfinder: ignore XGetErrorText(display, error->error_code, buf, sizeof(buf)); buf[sizeof(buf) - 1] = 0; - fprintf(stderr, "Got non-fatal X11 error: %s.\n", buf); + Log("Got non-fatal X11 error: %s", buf); return 0; } @@ -245,16 +246,14 @@ int parse_arguments(int argc, char **argv) { int i; for (i = 1; i < argc; ++i) { if (!strncmp(argv[i], "auth_", 5)) { - fprintf(stderr, - "Setting auth child name from command line is DEPRECATED.\nUse " - "the XSECURELOCK_AUTH environment variable instead.\n"); + Log("Setting auth child name from command line is DEPRECATED. Use " + "the XSECURELOCK_AUTH environment variable instead"); auth_executable = argv[i]; continue; } if (!strncmp(argv[i], "saver_", 6)) { - fprintf(stderr, - "Setting saver child name from command line is DEPRECATED.\nUse " - "the XSECURELOCK_SAVER environment variable instead.\n"); + Log("Setting saver child name from command line is DEPRECATED. Use " + "the XSECURELOCK_SAVER environment variable instead"); saver_executable = argv[i]; continue; } @@ -263,7 +262,7 @@ int parse_arguments(int argc, char **argv) { break; } // If we get here, the argument is unrecognized. Exit, then. - fprintf(stderr, "Unrecognized argument: %s.\n", argv[i]); + Log("Unrecognized argument: %s", argv[i]); return 0; } return 1; @@ -285,36 +284,36 @@ int check_settings() { // that could make the system un-unlockable. if (auth_executable == NULL) { - fprintf(stderr, "Auth module has not been specified in any way.\n"); + Log("Auth module has not been specified in any way"); return 0; } if (strncmp(auth_executable, "auth_", 5)) { - fprintf(stderr, "Auth module name must start with auth_.\n"); + Log("Auth module name must start with auth_"); return 0; } if (strchr(auth_executable, '.')) { - fprintf(stderr, "Auth module name may not contain a dot.\n"); + Log("Auth module name may not contain a dot"); return 0; } if (access(auth_executable, X_OK)) { // Flawfinder: ignore - fprintf(stderr, "Auth module must be executable.\n"); + Log("Auth module must be executable"); return 0; } if (saver_executable == NULL) { - fprintf(stderr, "Saver module has not been specified in any way.\n"); + Log("Saver module has not been specified in any way"); return 0; } if (strncmp(saver_executable, "saver_", 6)) { - fprintf(stderr, "Saver module name must start with saver_.\n"); + Log("Saver module name must start with saver_"); return 0; } if (strchr(saver_executable, '.')) { - fprintf(stderr, "Saver module name may not contain a dot.\n"); + Log("Saver module name may not contain a dot"); return 0; } if (access(saver_executable, X_OK)) { // Flawfinder: ignore - fprintf(stderr, "Saver module must be executable.\n"); + Log("Saver module must be executable"); return 0; } @@ -330,17 +329,17 @@ void MaybeRaiseWindow(Display *display, Window w) { Window *children, *siblings; unsigned int nchildren, nsiblings; if (!XQueryTree(display, w, &root, &parent, &children, &nchildren)) { - fprintf(stderr, "XQueryTree failed.\n"); + Log("XQueryTree failed"); return; } XFree(children); if (!XQueryTree(display, parent, &root, &grandparent, &siblings, &nsiblings)) { - fprintf(stderr, "XQueryTree failed.\n"); + Log("XQueryTree failed"); return; } if (nsiblings == 0) { - fprintf(stderr, "My parent window has no children.\n"); + Log("My parent window has no children"); XFree(siblings); return; } @@ -361,22 +360,21 @@ void MaybeRaiseWindow(Display *display, Window w) { void NotifyOfLock(int x11_fd) { int fd = GetIntSetting("XSS_SLEEP_LOCK_FD", -1); if (fd == x11_fd) { - fprintf(stderr, - "XSS_SLEEP_LOCK_FD matches DISPLAY - what?!? We're probably " - "inhibiting sleep now.\n"); + Log("XSS_SLEEP_LOCK_FD matches DISPLAY - what?!? We're probably " + "inhibiting sleep now"); } else if (fd != -1) { if (close(fd) != 0) { - perror("close(XSS_SLEEP_LOCK_FD)"); + LogErrno("close(XSS_SLEEP_LOCK_FD)"); } } if (notify_command != NULL && *notify_command != NULL) { pid_t pid = fork(); if (pid == -1) { - perror("fork"); + LogErrno("fork"); } else if (pid == 0) { // Child process. execvp(notify_command[0], notify_command); // Flawfinder: ignore - perror("execvp"); + LogErrno("execvp"); exit(EXIT_FAILURE); } else { // Parent process after successful fork. @@ -395,7 +393,7 @@ int main(int argc, char **argv) { // Change the current directory to HELPER_PATH so we don't need to process // path names. if (chdir(HELPER_PATH)) { - fprintf(stderr, "Could not switch to directory %s.\n", HELPER_PATH); + Log("Could not switch to directory %s", HELPER_PATH); return 1; } @@ -413,15 +411,14 @@ int main(int argc, char **argv) { // Connect to X11. Display *display = XOpenDisplay(NULL); if (display == NULL) { - fprintf(stderr, "Could not connect to $DISPLAY.\n"); + Log("Could not connect to $DISPLAY"); return 1; } // TODO(divVerent): Support that? if (ScreenCount(display) != 1) { - fprintf(stderr, - "Warning: 'Zaphod' configurations are not supported at this point. " - "Only locking the default screen.\n"); + Log("Warning: 'Zaphod' configurations are not supported at this point. " + "Only locking the default screen.\n"); } // Who's the root? @@ -432,7 +429,7 @@ int main(int argc, char **argv) { int w = DisplayWidth(display, DefaultScreen(display)); int h = DisplayHeight(display, DefaultScreen(display)); #ifdef DEBUG_EVENTS - fprintf(stderr, "DisplayWidthHeight %d %d\n", w, h); + Log("DisplayWidthHeight %d %d", w, h); #endif // Prepare some nice window attributes for a screen saver window. @@ -461,10 +458,10 @@ int main(int argc, char **argv) { &composite_minor_version) && (composite_major_version >= 1 || composite_minor_version >= 3); if (!have_composite) { - fprintf(stderr, "XComposite extension not detected.\n"); + Log("XComposite extension not detected"); } if (have_composite && no_composite) { - fprintf(stderr, "XComposite extension detected but disabled by user.\n"); + Log("XComposite extension detected but disabled by user"); have_composite = 0; } Window composite_window; @@ -533,7 +530,7 @@ int main(int argc, char **argv) { // Initialize XInput so we can get multibyte key events. XIM xim = XOpenIM(display, NULL, NULL, NULL); if (xim == NULL) { - fprintf(stderr, "XOpenIM failed. Assuming Latin-1 encoding.\n"); + Log("XOpenIM failed. Assuming Latin-1 encoding"); } XIC xic = NULL; if (xim != NULL) { @@ -557,7 +554,7 @@ int main(int argc, char **argv) { } } if (xic == NULL) { - fprintf(stderr, "XCreateIC failed. Assuming Latin-1 encoding.\n"); + Log("XCreateIC failed. Assuming Latin-1 encoding"); } } @@ -576,7 +573,7 @@ int main(int argc, char **argv) { // In case keys to disable grabs are available, turn them off for the duration // of the lock. if (XF86MiscSetGrabKeysState(display, False) != MiscExtGrabStateSuccess) { - fprintf(stderr, "Could not set grab keys state.\n"); + Log("Could not set grab keys state"); return 1; } #endif @@ -593,7 +590,7 @@ int main(int argc, char **argv) { nanosleep(&(const struct timespec){0, 100000000L}, NULL); } if (retries < 0) { - fprintf(stderr, "Could not grab pointer.\n"); + Log("Could not grab pointer"); return 1; } for (retries = 10; retries >= 0; --retries) { @@ -604,7 +601,7 @@ int main(int argc, char **argv) { nanosleep(&(const struct timespec){0, 100000000L}, NULL); } if (retries < 0) { - fprintf(stderr, "Could not grab keyboard.\n"); + Log("Could not grab keyboard"); return 1; } @@ -625,7 +622,7 @@ int main(int argc, char **argv) { int len; } priv; if (MLOCK_PAGE(&priv, sizeof(priv)) < 0) { - perror("mlock"); + LogErrno("mlock"); return 1; } @@ -669,11 +666,11 @@ int main(int argc, char **argv) { if (XGrabPointer(display, parent_window, False, ALL_POINTER_EVENTS, GrabModeAsync, GrabModeAsync, None, coverattrs.cursor, CurrentTime) != GrabSuccess) { - fprintf(stderr, "Critical: cannot re-grab pointer.\n"); + Log("Critical: cannot re-grab pointer"); } if (XGrabKeyboard(display, parent_window, False, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { - fprintf(stderr, "Critical: cannot re-grab keyboard.\n"); + Log("Critical: cannot re-grab keyboard"); } #endif @@ -699,21 +696,21 @@ int main(int argc, char **argv) { break; default: // Assume the child still lives. Shouldn't ever happen. - perror("waitpid"); + LogErrno("waitpid"); break; } } else if (pid == notify_command_pid) { if (WIFEXITED(status)) { // Done notifying. if (WEXITSTATUS(status) != EXIT_SUCCESS) { - fprintf(stderr, "Notification command failed with status %d.\n", - WEXITSTATUS(status)); + Log("Notification command failed with status %d", + WEXITSTATUS(status)); } notify_command_pid = 0; } // Otherwise it was suspended or whatever. We need to keep waiting. } else if (pid != 0) { - fprintf(stderr, "Unexpectedly woke up for PID %d.\n", (int)pid); + Log("Unexpectedly woke up for PID %d", (int)pid); } // Otherwise, we're still alive. Re-check next time. } @@ -727,16 +724,16 @@ int main(int argc, char **argv) { switch (priv.ev.type) { case ConfigureNotify: #ifdef DEBUG_EVENTS - fprintf(stderr, "ConfigureNotify %lu %d %d\n", - (unsigned long)priv.ev.xconfigure.window, - priv.ev.xconfigure.width, priv.ev.xconfigure.height); + Log("ConfigureNotify %lu %d %d", + (unsigned long)priv.ev.xconfigure.window, + priv.ev.xconfigure.width, priv.ev.xconfigure.height); #endif if (priv.ev.xconfigure.window == root_window) { // Root window size changed. Adjust the saver_window window too! w = priv.ev.xconfigure.width; h = priv.ev.xconfigure.height; #ifdef DEBUG_EVENTS - fprintf(stderr, "DisplayWidthHeight %d %d\n", w, h); + Log("DisplayWidthHeight %d %d", w, h); #endif XMoveResizeWindow(display, background_window, 0, 0, w, h); XMoveResizeWindow(display, saver_window, 0, 0, w, h); @@ -752,9 +749,9 @@ int main(int argc, char **argv) { break; case VisibilityNotify: #ifdef DEBUG_EVENTS - fprintf(stderr, "VisibilityNotify %lu %d\n", - (unsigned long)priv.ev.xvisibility.window, - priv.ev.xvisibility.state); + Log("VisibilityNotify %lu %d", + (unsigned long)priv.ev.xvisibility.window, + priv.ev.xvisibility.state); #endif if (priv.ev.xvisibility.state != VisibilityUnobscured) { // If something else shows an OverrideRedirect window, we want to @@ -764,9 +761,8 @@ int main(int argc, char **argv) { } else if (priv.ev.xvisibility.window == background_window) { XRaiseWindow(display, background_window); } else { - fprintf(stderr, - "Received unexpected VisibilityNotify for window %d.\n", - (int)priv.ev.xvisibility.window); + Log("Received unexpected VisibilityNotify for window %d", + (int)priv.ev.xvisibility.window); } } break; @@ -803,8 +799,7 @@ int main(int argc, char **argv) { } if (have_key && (size_t)priv.len >= sizeof(priv.buf)) { // Detect possible overruns. This should be unreachable. - fprintf(stderr, "Received invalid length from XLookupString: %d\n", - priv.len); + Log("Received invalid length from XLookupString: %d", priv.len); have_key = 0; } if (have_key) { @@ -833,8 +828,7 @@ int main(int argc, char **argv) { break; case MapNotify: #ifdef DEBUG_EVENTS - fprintf(stderr, "MapNotify %lu\n", - (unsigned long)priv.ev.xmap.window); + Log("MapNotify %lu", (unsigned long)priv.ev.xmap.window); #endif if (priv.ev.xmap.window == background_window) { background_window_mapped = 1; @@ -849,8 +843,7 @@ int main(int argc, char **argv) { break; case UnmapNotify: #ifdef DEBUG_EVENTS - fprintf(stderr, "UnmapNotify %lu\n", - (unsigned long)priv.ev.xmap.window); + Log("UnmapNotify %lu", (unsigned long)priv.ev.xmap.window); #endif if (priv.ev.xmap.window == background_window) { background_window_mapped = 0; @@ -860,36 +853,33 @@ int main(int argc, char **argv) { // This should never happen, but let's handle it anyway. // Compton might do this when --unredir-if-possible is set and a // fullscreen game launches while the screen is locked. - fprintf(stderr, "Someone unmapped our parent. Undoing that.\n"); + Log("Someone unmapped our parent. Undoing that"); XMapRaised(display, parent_window); } break; case FocusIn: case FocusOut: #ifdef DEBUG_EVENTS - fprintf(stderr, "Focus%d %lu\n", priv.ev.xfocus.mode, - (unsigned long)priv.ev.xfocus.window); + Log("Focus%d %lu", priv.ev.xfocus.mode, + (unsigned long)priv.ev.xfocus.window); #endif if (priv.ev.xfocus.window == parent_window && priv.ev.xfocus.mode == NotifyUngrab) { - fprintf(stderr, "WARNING: lost grab, trying to grab again.\n"); + Log("WARNING: lost grab, trying to grab again"); if (XGrabKeyboard(display, parent_window, False, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess) { - fprintf(stderr, - "Critical: lost grab but cannot re-grab keyboard.\n"); + Log("Critical: lost grab but cannot re-grab keyboard"); } if (XGrabPointer(display, parent_window, False, ALL_POINTER_EVENTS, GrabModeAsync, GrabModeAsync, None, None, CurrentTime) != GrabSuccess) { - fprintf(stderr, - "Critical: lost grab but cannot re-grab pointer.\n"); + Log("Critical: lost grab but cannot re-grab pointer"); } } break; default: #ifdef DEBUG_EVENTS - fprintf(stderr, "Event%d %lu\n", priv.ev.type, - (unsigned long)priv.ev.xany.window); + Log("Event%d %lu", priv.ev.type, (unsigned long)priv.ev.xany.window); #endif #ifdef HAVE_SCRNSAVER // Handle screen saver notifications. If the screen is blanked anyway, @@ -904,7 +894,7 @@ int main(int argc, char **argv) { break; } #endif - fprintf(stderr, "Received unexpected event %d.\n", priv.ev.type); + Log("Received unexpected event %d", priv.ev.type); break; } } diff --git a/mlock_page.h b/mlock_page.h index 663114d7..377b4857 100644 --- a/mlock_page.h +++ b/mlock_page.h @@ -33,11 +33,11 @@ limitations under the License. * * The area is expanded to fill whole memory pages. */ -#define MLOCK_PAGE(ptr, size) \ - mlock((void *)((((uintptr_t)(ptr)) / (uintptr_t)PAGESIZE) * \ - (uintptr_t)PAGESIZE), \ - (((uintptr_t)(ptr) + (size)-1) / (uintptr_t)PAGESIZE - \ - ((uintptr_t)(ptr)) / (uintptr_t)PAGESIZE + 1) * \ +#define MLOCK_PAGE(ptr, size) \ + mlock((void *)((((uintptr_t)(ptr)) / (uintptr_t)PAGESIZE) * \ + (uintptr_t)PAGESIZE), \ + (((uintptr_t)(ptr) + (size)-1) / (uintptr_t)PAGESIZE - \ + ((uintptr_t)(ptr)) / (uintptr_t)PAGESIZE + 1) * \ (uintptr_t)PAGESIZE) #elif _POSIX_MEMLOCK > 0 #warning mlock() is unavailable. More memory will be locked than necessary. diff --git a/saver_child.c b/saver_child.c index 1fdffca2..ffb3c000 100644 --- a/saver_child.c +++ b/saver_child.c @@ -17,13 +17,13 @@ limitations under the License. #include "saver_child.h" #include // for ECHILD, EINTR, errno -#include // for kill, SIGTERM -#include // for perror, fprintf, NULL, etc -#include // for exit, EXIT_FAILURE, etc -#include // for WEXITSTATUS, waitpid, etc +#include // for kill, SIGTERM, sigemptyset, sigprocmask +#include // for NULL, exit, EXIT_FAILURE, EXIT_SUCCESS +#include // for WEXITSTATUS, WIFEXITED, WIFSIGNALED #include // for pid_t, execl, fork, setsid -#include "xscreensaver_api.h" +#include "logging.h" // for Log, LogErrno +#include "xscreensaver_api.h" // for ExportWindowID //! The PIDs of currently running saver children, or 0 if not running. static pid_t saver_child_pid[MAX_SAVERS] = {0}; @@ -31,8 +31,7 @@ static pid_t saver_child_pid[MAX_SAVERS] = {0}; void WatchSaverChild(Display* dpy, Window w, int index, const char* executable, int should_be_running) { if (index < 0 || index >= MAX_SAVERS) { - fprintf(stderr, "Saver index out of range: !(0 <= %d < %d).", index, - MAX_SAVERS); + Log("Saver index out of range: !(0 <= %d < %d)", index, MAX_SAVERS); return; } @@ -61,7 +60,7 @@ void WatchSaverChild(Display* dpy, Window w, int index, const char* executable, break; default: // Assume the child still lives. Shouldn't ever happen. - perror("waitpid"); + LogErrno("waitpid"); break; } } else if (pid == saver_child_pid[index]) { @@ -75,21 +74,19 @@ void WatchSaverChild(Display* dpy, Window w, int index, const char* executable, saver_child_pid[index] = 0; if (WIFSIGNALED(status) && (should_be_running || WTERMSIG(status) != SIGTERM)) { - fprintf(stderr, "Saver child killed by signal %d.\n", - WTERMSIG(status)); + Log("Saver child killed by signal %d", WTERMSIG(status)); } if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) { - fprintf(stderr, "Saver child failed with status %d.\n", - WEXITSTATUS(status)); + Log("Saver child failed with status %d", WEXITSTATUS(status)); } // Now is the time to remove anything the child may have displayed. XClearWindow(dpy, w); } // Otherwise it was suspended or whatever. We need to keep waiting. } else if (pid != 0) { - fprintf(stderr, "Unexpectedly woke up for PID %d.\n", (int)pid); + Log("Unexpectedly woke up for PID %d", (int)pid); } else if (!should_be_running) { - fprintf(stderr, "Unexpectedly woke up for PID 0 despite no WNOHANG.\n"); + Log("Unexpectedly woke up for PID 0 despite no WNOHANG"); } // Otherwise, we're still alive. } while (!should_be_running && saver_child_pid[index] != 0); @@ -98,7 +95,7 @@ void WatchSaverChild(Display* dpy, Window w, int index, const char* executable, if (should_be_running && saver_child_pid[index] == 0) { pid_t pid = fork(); if (pid == -1) { - perror("fork"); + LogErrno("fork"); } else if (pid == 0) { // Child process. setsid(); @@ -111,7 +108,7 @@ void WatchSaverChild(Display* dpy, Window w, int index, const char* executable, ExportWindowID(w); execl(executable, executable, NULL); // Flawfinder: ignore - perror("execl"); + LogErrno("execl"); exit(EXIT_FAILURE); } else { // Parent process after successful fork. diff --git a/test/break-compositor.c b/test/break-compositor.c index 5b3011ee..cceb6517 100644 --- a/test/break-compositor.c +++ b/test/break-compositor.c @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include diff --git a/test/get-compositor.c b/test/get-compositor.c index f5d41525..abc866c1 100644 --- a/test/get-compositor.c +++ b/test/get-compositor.c @@ -9,10 +9,10 @@ int main() { fprintf(stderr, "Could not connect to $DISPLAY.\n"); return 1; } - char buf[32]; // Flawfinder: ignore + char buf[32]; // Flawfinder: ignore snprintf(buf, sizeof(buf), "_NET_WM_CM_S%d", // Flawfinder: ignore (int)DefaultScreen(display)); - buf[sizeof(buf)-1] = 0; + buf[sizeof(buf) - 1] = 0; Atom atom = XInternAtom(display, buf, False); Window w = XGetSelectionOwner(display, atom); if (w == None) { diff --git a/xscreensaver_api.c b/xscreensaver_api.c index ebe18ceb..fe3a7ec0 100644 --- a/xscreensaver_api.c +++ b/xscreensaver_api.c @@ -21,6 +21,7 @@ limitations under the License. #include // for setenv #include "env_settings.h" // for GetUnsignedLongLongSetting +#include "logging.h" void ExportWindowID(Window w) { char window_id_str[32]; // Flawfinder: ignore @@ -28,7 +29,7 @@ void ExportWindowID(Window w) { snprintf(window_id_str, sizeof(window_id_str), // Flawfinder: ignore "%llu", (unsigned long long)w); if (window_id_len <= 0 || (size_t)window_id_len >= sizeof(window_id_str)) { - fprintf(stderr, "Window ID doesn't fit into buffer.\n"); + Log("Window ID doesn't fit into buffer"); return; } setenv("XSCREENSAVER_WINDOW", window_id_str, 1);