1 /*- 2 * Copyright (c) 2011 Dag-Erling Smørgrav 3 * 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 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote 15 * products derived from this software without specific prior written 16 * permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: pamtest.c 595 2012-04-14 14:28:35Z des $ 31 */ 32 33 #ifdef HAVE_CONFIG_H 34 # include "config.h" 35 #endif 36 37 #include <err.h> 38 #include <pwd.h> 39 #include <stdarg.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <security/pam_appl.h> 46 #include <security/openpam.h> /* for openpam_ttyconv() */ 47 48 /* OpenPAM internals */ 49 extern const char *pam_item_name[PAM_NUM_ITEMS]; 50 extern int openpam_debug; 51 52 static pam_handle_t *pamh; 53 static struct pam_conv pamc; 54 55 static int silent; 56 static int verbose; 57 58 static void pt_verbose(const char *, ...) 59 OPENPAM_FORMAT ((__printf__, 1, 2)); 60 static void pt_error(int, const char *, ...) 61 OPENPAM_FORMAT ((__printf__, 2, 3)); 62 63 /* 64 * Print an information message if -v was specified at least once 65 */ 66 static void 67 pt_verbose(const char *fmt, ...) 68 { 69 va_list ap; 70 71 if (verbose) { 72 va_start(ap, fmt); 73 vfprintf(stderr, fmt, ap); 74 va_end(ap); 75 fprintf(stderr, "\n"); 76 } 77 } 78 79 /* 80 * Print an error message 81 */ 82 static void 83 pt_error(int e, const char *fmt, ...) 84 { 85 va_list ap; 86 87 if (e == PAM_SUCCESS && !verbose) 88 return; 89 va_start(ap, fmt); 90 vfprintf(stderr, fmt, ap); 91 va_end(ap); 92 fprintf(stderr, ": %s\n", pam_strerror(NULL, e)); 93 } 94 95 /* 96 * Wrapper for pam_start(3) 97 */ 98 static int 99 pt_start(const char *service, const char *user) 100 { 101 int pame; 102 103 pamc.conv = &openpam_ttyconv; 104 pt_verbose("pam_start(%s, %s)", service, user); 105 if ((pame = pam_start(service, user, &pamc, &pamh)) != PAM_SUCCESS) 106 pt_error(pame, "pam_start(%s)", service); 107 return (pame); 108 } 109 110 /* 111 * Wrapper for pam_authenticate(3) 112 */ 113 static int 114 pt_authenticate(int flags) 115 { 116 int pame; 117 118 flags |= silent; 119 if ((pame = pam_authenticate(pamh, flags)) != PAM_SUCCESS) 120 pt_error(pame, "pam_authenticate()"); 121 return (pame); 122 } 123 124 /* 125 * Wrapper for pam_acct_mgmt(3) 126 */ 127 static int 128 pt_acct_mgmt(int flags) 129 { 130 int pame; 131 132 flags |= silent; 133 if ((pame = pam_acct_mgmt(pamh, flags)) != PAM_SUCCESS) 134 pt_error(pame, "pam_acct_mgmt()"); 135 return (pame); 136 } 137 138 /* 139 * Wrapper for pam_chauthtok(3) 140 */ 141 static int 142 pt_chauthtok(int flags) 143 { 144 int pame; 145 146 flags |= silent; 147 if ((pame = pam_chauthtok(pamh, flags)) != PAM_SUCCESS) 148 pt_error(pame, "pam_chauthtok()"); 149 return (pame); 150 } 151 152 /* 153 * Wrapper for pam_setcred(3) 154 */ 155 static int 156 pt_setcred(int flags) 157 { 158 int pame; 159 160 flags |= silent; 161 if ((pame = pam_setcred(pamh, flags)) != PAM_SUCCESS) 162 pt_error(pame, "pam_setcred()"); 163 return (pame); 164 } 165 166 /* 167 * Wrapper for pam_open_session(3) 168 */ 169 static int 170 pt_open_session(int flags) 171 { 172 int pame; 173 174 flags |= silent; 175 if ((pame = pam_open_session(pamh, flags)) != PAM_SUCCESS) 176 pt_error(pame, "pam_open_session()"); 177 return (pame); 178 } 179 180 /* 181 * Wrapper for pam_close_session(3) 182 */ 183 static int 184 pt_close_session(int flags) 185 { 186 int pame; 187 188 flags |= silent; 189 if ((pame = pam_close_session(pamh, flags)) != PAM_SUCCESS) 190 pt_error(pame, "pam_close_session()"); 191 return (pame); 192 } 193 194 /* 195 * Wrapper for pam_set_item(3) 196 */ 197 static int 198 pt_set_item(int item, const char *p) 199 { 200 int pame; 201 202 switch (item) { 203 case PAM_SERVICE: 204 case PAM_USER: 205 case PAM_AUTHTOK: 206 case PAM_OLDAUTHTOK: 207 case PAM_TTY: 208 case PAM_RHOST: 209 case PAM_RUSER: 210 case PAM_USER_PROMPT: 211 case PAM_AUTHTOK_PROMPT: 212 case PAM_OLDAUTHTOK_PROMPT: 213 case PAM_HOST: 214 pt_verbose("setting %s to %s", pam_item_name[item], p); 215 break; 216 default: 217 pt_verbose("setting %s", pam_item_name[item]); 218 break; 219 } 220 if ((pame = pam_set_item(pamh, item, p)) != PAM_SUCCESS) 221 pt_error(pame, "pam_set_item(%s)", pam_item_name[item]); 222 return (pame); 223 } 224 225 /* 226 * Wrapper for pam_end(3) 227 */ 228 static int 229 pt_end(int pame) 230 { 231 232 if (pamh != NULL && (pame = pam_end(pamh, pame)) != PAM_SUCCESS) 233 /* can't happen */ 234 pt_error(pame, "pam_end()"); 235 return (pame); 236 } 237 238 /* 239 * Retrieve and list the PAM environment variables 240 */ 241 static int 242 pt_listenv(void) 243 { 244 char **pam_envlist, **pam_env; 245 246 if ((pam_envlist = pam_getenvlist(pamh)) == NULL || 247 *pam_envlist == NULL) { 248 pt_verbose("no environment variables."); 249 } else { 250 pt_verbose("environment variables:"); 251 for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) { 252 printf(" %s\n", *pam_env); 253 free(*pam_env); 254 } 255 } 256 free(pam_envlist); 257 return (PAM_SUCCESS); 258 } 259 260 /* 261 * Print usage string and exit 262 */ 263 static void 264 usage(void) 265 { 266 267 fprintf(stderr, "usage: pamtest %s service command ...\n", 268 "[-dkMPsv] [-H rhost] [-h host] [-t tty] [-U ruser] [-u user]"); 269 exit(1); 270 } 271 272 /* 273 * Handle an option that takes a string argument and can be used only once 274 */ 275 static void 276 opt_str_once(int opt, const char **p, const char *arg) 277 { 278 279 if (*p != NULL) { 280 fprintf(stderr, "The -%c option can only be used once\n", opt); 281 usage(); 282 } 283 *p = arg; 284 } 285 286 /* 287 * Entry point 288 */ 289 int 290 main(int argc, char *argv[]) 291 { 292 char hostname[1024]; 293 const char *rhost = NULL; 294 const char *host = NULL; 295 const char *ruser = NULL; 296 const char *user = NULL; 297 const char *service = NULL; 298 const char *tty = NULL; 299 int keepatit = 0; 300 int pame; 301 int opt; 302 303 while ((opt = getopt(argc, argv, "dH:h:kMPst:U:u:v")) != -1) 304 switch (opt) { 305 case 'd': 306 openpam_debug++; 307 break; 308 case 'H': 309 opt_str_once(opt, &rhost, optarg); 310 break; 311 case 'h': 312 opt_str_once(opt, &host, optarg); 313 break; 314 case 'k': 315 keepatit = 1; 316 break; 317 case 'M': 318 openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0); 319 openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0); 320 break; 321 case 'P': 322 openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0); 323 openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0); 324 break; 325 case 's': 326 silent = PAM_SILENT; 327 break; 328 case 't': 329 opt_str_once(opt, &tty, optarg); 330 break; 331 case 'U': 332 opt_str_once(opt, &ruser, optarg); 333 break; 334 case 'u': 335 opt_str_once(opt, &user, optarg); 336 break; 337 case 'v': 338 verbose++; 339 break; 340 default: 341 usage(); 342 } 343 344 argc -= optind; 345 argv += optind; 346 347 if (argc < 1) 348 usage(); 349 350 service = *argv; 351 --argc; 352 ++argv; 353 354 /* defaults */ 355 if (rhost == NULL) { 356 if (gethostname(hostname, sizeof(hostname)) == -1) 357 err(1, "gethostname()"); 358 rhost = hostname; 359 } 360 if (tty == NULL) 361 tty = ttyname(STDERR_FILENO); 362 if (user == NULL) 363 user = getlogin(); 364 if (ruser == NULL) 365 ruser = user; 366 367 /* initialize PAM */ 368 if ((pame = pt_start(service, user)) != PAM_SUCCESS) 369 goto end; 370 371 /* 372 * pam_start(3) sets this to the machine's hostname, but we allow 373 * the user to override it. 374 */ 375 if (host != NULL) 376 if ((pame = pt_set_item(PAM_HOST, host)) != PAM_SUCCESS) 377 goto end; 378 379 /* 380 * The remote host / user / tty are usually set by the 381 * application. 382 */ 383 if ((pame = pt_set_item(PAM_RHOST, rhost)) != PAM_SUCCESS || 384 (pame = pt_set_item(PAM_RUSER, ruser)) != PAM_SUCCESS || 385 (pame = pt_set_item(PAM_TTY, tty)) != PAM_SUCCESS) 386 goto end; 387 388 while (argc > 0) { 389 if (strcmp(*argv, "listenv") == 0 || 390 strcmp(*argv, "env") == 0) { 391 pame = pt_listenv(); 392 } else if (strcmp(*argv, "authenticate") == 0 || 393 strcmp(*argv, "auth") == 0) { 394 pame = pt_authenticate(0); 395 } else if (strcmp(*argv, "acct_mgmt") == 0 || 396 strcmp(*argv, "account") == 0) { 397 pame = pt_acct_mgmt(0); 398 } else if (strcmp(*argv, "chauthtok") == 0 || 399 strcmp(*argv, "change") == 0) { 400 pame = pt_chauthtok(PAM_CHANGE_EXPIRED_AUTHTOK); 401 } else if (strcmp(*argv, "forcechauthtok") == 0 || 402 strcmp(*argv, "forcechange") == 0) { 403 pame = pt_chauthtok(0); 404 } else if (strcmp(*argv, "setcred") == 0 || 405 strcmp(*argv, "establish_cred") == 0) { 406 pame = pt_setcred(PAM_ESTABLISH_CRED); 407 } else if (strcmp(*argv, "open_session") == 0 || 408 strcmp(*argv, "open") == 0) { 409 pame = pt_open_session(0); 410 } else if (strcmp(*argv, "close_session") == 0 || 411 strcmp(*argv, "close") == 0) { 412 pame = pt_close_session(0); 413 } else if (strcmp(*argv, "unsetcred") == 0 || 414 strcmp(*argv, "delete_cred") == 0) { 415 pame = pt_setcred(PAM_DELETE_CRED); 416 } else { 417 warnx("unknown primitive: %s", *argv); 418 pame = PAM_SYSTEM_ERR; 419 } 420 if (pame != PAM_SUCCESS && !keepatit) { 421 warnx("test aborted"); 422 break; 423 } 424 --argc; 425 ++argv; 426 } 427 428 end: 429 (void)pt_end(pame); 430 exit(pame == PAM_SUCCESS ? 0 : 1); 431 } 432