openpam_configure.c revision 94670
1/*- 2 * Copyright (c) 2002 Networks Associates Technology, Inc. 3 * All rights reserved. 4 * 5 * This software was developed for the FreeBSD Project by ThinkSec AS and 6 * NAI Labs, the Security Research Division of Network Associates, Inc. 7 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 8 * DARPA CHATS research program. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote 19 * products derived from this software without specific prior written 20 * permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $P4: //depot/projects/openpam/lib/openpam_configure.c#1 $ 35 */ 36 37#include <ctype.h> 38#include <errno.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42 43#include <security/pam_appl.h> 44 45#include "openpam_impl.h" 46 47#define PAM_CONF_STYLE 0 48#define PAM_D_STYLE 1 49#define MAX_LINE_LEN 1024 50#define MAX_OPTIONS 256 51 52static int 53openpam_read_policy_file(pam_handle_t *pamh, 54 const char *service, 55 const char *filename, 56 int style) 57{ 58 char buf[MAX_LINE_LEN], *p, *q; 59 const char *optv[MAX_OPTIONS + 1]; 60 int ch, chain, flag, line, optc, n, r; 61 size_t len; 62 FILE *f; 63 64 n = 0; 65 66 if ((f = fopen(filename, "r")) == NULL) { 67 openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_NOTICE, 68 "%s: %m", filename); 69 return (0); 70 } 71 openpam_log(PAM_LOG_DEBUG, "looking for '%s' in %s", 72 service, filename); 73 74 for (line = 1; fgets(buf, MAX_LINE_LEN, f) != NULL; ++line) { 75 if ((len = strlen(buf)) == 0) 76 continue; 77 78 /* check for overflow */ 79 if (buf[--len] != '\n' && !feof(f)) { 80 openpam_log(PAM_LOG_ERROR, "%s: line %d too long", 81 filename, line); 82 openpam_log(PAM_LOG_ERROR, "%s: ignoring line %d", 83 filename, line); 84 while ((ch = fgetc(f)) != EOF) 85 if (ch == '\n') 86 break; 87 continue; 88 } 89 90 /* strip comments and trailing whitespace */ 91 if ((p = strchr(buf, '#')) != NULL) 92 len = p - buf ? p - buf - 1 : p - buf; 93 while (len > 0 && isspace(buf[len - 1])) 94 --len; 95 if (len == 0) 96 continue; 97 buf[len] = '\0'; 98 p = q = buf; 99 100 /* check service name */ 101 if (style == PAM_CONF_STYLE) { 102 for (q = p = buf; *q != '\0' && !isspace(*q); ++q) 103 /* nothing */; 104 if (*q == '\0') 105 goto syntax_error; 106 *q++ = '\0'; 107 if (strcmp(p, service) != 0) 108 continue; 109 openpam_log(PAM_LOG_DEBUG, "%s: line %d matches '%s'", 110 filename, line, service); 111 } 112 113 114 /* get module type */ 115 for (p = q; isspace(*p); ++p) 116 /* nothing */; 117 for (q = p; *q != '\0' && !isspace(*q); ++q) 118 /* nothing */; 119 if (q == p || *q == '\0') 120 goto syntax_error; 121 *q++ = '\0'; 122 if (strcmp(p, "auth") == 0) { 123 chain = PAM_AUTH; 124 } else if (strcmp(p, "account") == 0) { 125 chain = PAM_ACCOUNT; 126 } else if (strcmp(p, "session") == 0) { 127 chain = PAM_SESSION; 128 } else if (strcmp(p, "password") == 0) { 129 chain = PAM_PASSWORD; 130 } else { 131 openpam_log(PAM_LOG_ERROR, 132 "%s: invalid module type on line %d: '%s'", 133 filename, line, p); 134 continue; 135 } 136 137 /* get control flag */ 138 for (p = q; isspace(*p); ++p) 139 /* nothing */; 140 for (q = p; *q != '\0' && !isspace(*q); ++q) 141 /* nothing */; 142 if (q == p || *q == '\0') 143 goto syntax_error; 144 *q++ = '\0'; 145 if (strcmp(p, "required") == 0) { 146 flag = PAM_REQUIRED; 147 } else if (strcmp(p, "requisite") == 0) { 148 flag = PAM_REQUISITE; 149 } else if (strcmp(p, "sufficient") == 0) { 150 flag = PAM_SUFFICIENT; 151 } else if (strcmp(p, "optional") == 0) { 152 flag = PAM_OPTIONAL; 153 } else { 154 openpam_log(PAM_LOG_ERROR, 155 "%s: invalid control flag on line %d: '%s'", 156 filename, line, p); 157 continue; 158 } 159 160 /* get module name */ 161 for (p = q; isspace(*p); ++p) 162 /* nothing */; 163 for (q = p; *q != '\0' && !isspace(*q); ++q) 164 /* nothing */; 165 if (q == p) 166 goto syntax_error; 167 168 /* get options */ 169 for (optc = 0; *q != '\0' && optc < MAX_OPTIONS; ++optc) { 170 *q++ = '\0'; 171 while (isspace(*q)) 172 ++q; 173 optv[optc] = q; 174 while (*q != '\0' && !isspace(*q)) 175 ++q; 176 } 177 optv[optc] = NULL; 178 if (*q != '\0') { 179 *q = '\0'; 180 openpam_log(PAM_LOG_ERROR, 181 "%s: too many options on line %d", 182 filename, line); 183 } 184 185 /* 186 * Finally, add the module at the end of the 187 * appropriate chain and bump the counter. 188 */ 189 r = openpam_add_module(pamh, chain, flag, p, optc, optv); 190 if (r != PAM_SUCCESS) 191 return (-r); 192 ++n; 193 continue; 194 syntax_error: 195 openpam_log(PAM_LOG_ERROR, "%s: syntax error on line %d", 196 filename, line); 197 openpam_log(PAM_LOG_DEBUG, "%s: line %d: [%s]", 198 filename, line, q); 199 openpam_log(PAM_LOG_ERROR, "%s: ignoring line %d", 200 filename, line); 201 } 202 203 if (ferror(f)) 204 openpam_log(PAM_LOG_ERROR, "%s: %m", filename); 205 206 fclose(f); 207 return (n); 208} 209 210static const char *openpam_policy_path[] = { 211 "/etc/pam.d/", 212 "/etc/pam.conf", 213 "/usr/local/etc/pam.d/", 214 NULL 215}; 216 217/* 218 * OpenPAM internal 219 * 220 * Configure a service 221 */ 222 223int 224openpam_configure(pam_handle_t *pamh, 225 const char *service) 226{ 227 const char **path; 228 char *filename; 229 size_t len; 230 int r; 231 232 for (path = openpam_policy_path; *path != NULL; ++path) { 233 len = strlen(*path); 234 if ((*path)[len - 1] == '/') { 235 filename = malloc(len + strlen(service) + 1); 236 if (filename == NULL) { 237 openpam_log(PAM_LOG_ERROR, "malloc(): %m"); 238 return (PAM_BUF_ERR); 239 } 240 strcpy(filename, *path); 241 strcat(filename, service); 242 r = openpam_read_policy_file(pamh, 243 service, filename, PAM_D_STYLE); 244 free(filename); 245 } else { 246 r = openpam_read_policy_file(pamh, 247 service, *path, PAM_CONF_STYLE); 248 } 249 if (r < 0) 250 return (-r); 251 if (r > 0) 252 return (PAM_SUCCESS); 253 } 254 255 return (PAM_SYSTEM_ERR); 256} 257 258/* 259 * NODOC 260 * 261 * Error codes: 262 * PAM_SYSTEM_ERR 263 * PAM_BUF_ERR 264 */ 265