1 /* 2 * Logging functions for the fake PAM library, used for testing. 3 * 4 * This file contains the implementation of pam_syslog and pam_vsyslog, which 5 * log to an internal buffer rather than to syslog, and the testing function 6 * used to recover that buffer. It also includes the pam_strerror 7 * implementation. 8 * 9 * The canonical version of this file is maintained in the rra-c-util package, 10 * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>. 11 * 12 * Written by Russ Allbery <eagle@eyrie.org> 13 * Copyright 2020 Russ Allbery <eagle@eyrie.org> 14 * Copyright 2010-2012, 2014 15 * The Board of Trustees of the Leland Stanford Junior University 16 * 17 * Permission is hereby granted, free of charge, to any person obtaining a 18 * copy of this software and associated documentation files (the "Software"), 19 * to deal in the Software without restriction, including without limitation 20 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 21 * and/or sell copies of the Software, and to permit persons to whom the 22 * Software is furnished to do so, subject to the following conditions: 23 * 24 * The above copyright notice and this permission notice shall be included in 25 * all copies or substantial portions of the Software. 26 * 27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 33 * DEALINGS IN THE SOFTWARE. 34 * 35 * SPDX-License-Identifier: MIT 36 */ 37 38 #include <config.h> 39 #include <portable/pam.h> 40 #include <portable/system.h> 41 42 #include <tests/fakepam/internal.h> 43 #include <tests/fakepam/pam.h> 44 #include <tests/tap/basic.h> 45 #include <tests/tap/string.h> 46 47 /* Used for unused parameters to silence gcc warnings. */ 48 #define UNUSED __attribute__((__unused__)) 49 50 /* The struct used to accumulate log messages. */ 51 static struct output *messages = NULL; 52 53 54 /* 55 * Allocate a new, empty output struct and call bail if memory allocation 56 * fails. 57 */ 58 struct output * 59 output_new(void) 60 { 61 struct output *output; 62 63 output = bmalloc(sizeof(struct output)); 64 output->count = 0; 65 output->allocated = 1; 66 output->lines = bmalloc(sizeof(output->lines[0])); 67 output->lines[0].line = NULL; 68 return output; 69 } 70 71 72 /* 73 * Add a new output line to the output struct, resizing the array as 74 * necessary. Calls bail if memory allocation fails. 75 */ 76 void 77 output_add(struct output *output, int priority, const char *string) 78 { 79 size_t next = output->count; 80 size_t size, n; 81 82 if (output->count == output->allocated) { 83 n = output->allocated + 1; 84 size = sizeof(output->lines[0]); 85 output->lines = breallocarray(output->lines, n, size); 86 output->allocated = n; 87 } 88 output->lines[next].priority = priority; 89 output->lines[next].line = bstrdup(string); 90 output->count++; 91 } 92 93 94 /* 95 * Return the error string associated with the PAM error code. We do this as 96 * a giant case statement so that we don't assume anything about the error 97 * codes used by the system PAM library. 98 */ 99 const char * 100 pam_strerror(PAM_STRERROR_CONST pam_handle_t *pamh UNUSED, int code) 101 { 102 /* clang-format off */ 103 switch (code) { 104 case PAM_SUCCESS: return "No error"; 105 case PAM_OPEN_ERR: return "Failure loading service module"; 106 case PAM_SYMBOL_ERR: return "Symbol not found"; 107 case PAM_SERVICE_ERR: return "Error in service module"; 108 case PAM_SYSTEM_ERR: return "System error"; 109 case PAM_BUF_ERR: return "Memory buffer error"; 110 default: return "Unknown error"; 111 } 112 /* clang-format on */ 113 } 114 115 116 /* 117 * Log a message using variadic arguments. Just a wrapper around 118 * pam_vsyslog. 119 */ 120 void 121 pam_syslog(const pam_handle_t *pamh, int priority, const char *format, ...) 122 { 123 va_list args; 124 125 va_start(args, format); 126 pam_vsyslog(pamh, priority, format, args); 127 va_end(args); 128 } 129 130 131 /* 132 * Log a PAM error message with a given priority. Just appends the priority, 133 * a space, and the error message, followed by a newline, to the internal 134 * buffer, allocating new space if needed. Ignore memory allocation failures; 135 * we have no way of reporting them, but the tests will fail due to missing 136 * output. 137 */ 138 void 139 pam_vsyslog(const pam_handle_t *pamh UNUSED, int priority, const char *format, 140 va_list args) 141 { 142 char *message = NULL; 143 144 bvasprintf(&message, format, args); 145 if (messages == NULL) 146 messages = output_new(); 147 output_add(messages, priority, message); 148 free(message); 149 } 150 151 152 /* 153 * Used by test code. Returns the accumulated messages in an output struct 154 * and starts a new one. Caller is responsible for freeing with 155 * pam_output_free. 156 */ 157 struct output * 158 pam_output(void) 159 { 160 struct output *output; 161 162 output = messages; 163 messages = NULL; 164 return output; 165 } 166 167 168 /* 169 * Free an output struct. 170 */ 171 void 172 pam_output_free(struct output *output) 173 { 174 size_t i; 175 176 if (output == NULL) 177 return; 178 for (i = 0; i < output->count; i++) 179 if (output->lines[i].line != NULL) 180 free(output->lines[i].line); 181 free(output->lines); 182 free(output); 183 } 184