1228690Sdes/*- 2228690Sdes * Copyright (c) 2011 Dag-Erling Sm��rgrav 3228690Sdes * All rights reserved. 4228690Sdes * 5228690Sdes * Redistribution and use in source and binary forms, with or without 6228690Sdes * modification, are permitted provided that the following conditions 7228690Sdes * are met: 8228690Sdes * 1. Redistributions of source code must retain the above copyright 9263421Sdes * notice, this list of conditions and the following disclaimer. 10228690Sdes * 2. Redistributions in binary form must reproduce the above copyright 11228690Sdes * notice, this list of conditions and the following disclaimer in the 12228690Sdes * documentation and/or other materials provided with the distribution. 13247568Sdes * 3. The name of the author may not be used to endorse or promote 14247568Sdes * products derived from this software without specific prior written 15247568Sdes * permission. 16228690Sdes * 17228690Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18228690Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19228690Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20228690Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21228690Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22228690Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23228690Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24228690Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25228690Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26228690Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27228690Sdes * SUCH DAMAGE. 28228690Sdes * 29263421Sdes * $Id: pamtest.c 685 2013-07-11 16:33:34Z des $ 30228690Sdes */ 31228690Sdes 32228690Sdes#ifdef HAVE_CONFIG_H 33228690Sdes# include "config.h" 34228690Sdes#endif 35228690Sdes 36228690Sdes#include <err.h> 37263421Sdes#include <limits.h> 38228690Sdes#include <pwd.h> 39228690Sdes#include <stdarg.h> 40228690Sdes#include <stdio.h> 41228690Sdes#include <stdlib.h> 42228690Sdes#include <string.h> 43228690Sdes#include <unistd.h> 44228690Sdes 45228690Sdes#include <security/pam_appl.h> 46228690Sdes#include <security/openpam.h> /* for openpam_ttyconv() */ 47228690Sdes 48228690Sdes/* OpenPAM internals */ 49228690Sdesextern const char *pam_item_name[PAM_NUM_ITEMS]; 50228690Sdesextern int openpam_debug; 51228690Sdes 52228690Sdesstatic pam_handle_t *pamh; 53228690Sdesstatic struct pam_conv pamc; 54228690Sdes 55228690Sdesstatic int silent; 56228690Sdesstatic int verbose; 57228690Sdes 58228690Sdesstatic void pt_verbose(const char *, ...) 59228690Sdes OPENPAM_FORMAT ((__printf__, 1, 2)); 60228690Sdesstatic void pt_error(int, const char *, ...) 61228690Sdes OPENPAM_FORMAT ((__printf__, 2, 3)); 62228690Sdes 63228690Sdes/* 64228690Sdes * Print an information message if -v was specified at least once 65228690Sdes */ 66228690Sdesstatic void 67228690Sdespt_verbose(const char *fmt, ...) 68228690Sdes{ 69228690Sdes va_list ap; 70228690Sdes 71228690Sdes if (verbose) { 72228690Sdes va_start(ap, fmt); 73228690Sdes vfprintf(stderr, fmt, ap); 74228690Sdes va_end(ap); 75228690Sdes fprintf(stderr, "\n"); 76228690Sdes } 77228690Sdes} 78228690Sdes 79228690Sdes/* 80228690Sdes * Print an error message 81228690Sdes */ 82228690Sdesstatic void 83228690Sdespt_error(int e, const char *fmt, ...) 84228690Sdes{ 85228690Sdes va_list ap; 86228690Sdes 87228690Sdes if (e == PAM_SUCCESS && !verbose) 88228690Sdes return; 89228690Sdes va_start(ap, fmt); 90228690Sdes vfprintf(stderr, fmt, ap); 91228690Sdes va_end(ap); 92228690Sdes fprintf(stderr, ": %s\n", pam_strerror(NULL, e)); 93228690Sdes} 94228690Sdes 95228690Sdes/* 96228690Sdes * Wrapper for pam_start(3) 97228690Sdes */ 98228690Sdesstatic int 99228690Sdespt_start(const char *service, const char *user) 100228690Sdes{ 101228690Sdes int pame; 102228690Sdes 103228690Sdes pamc.conv = &openpam_ttyconv; 104228690Sdes pt_verbose("pam_start(%s, %s)", service, user); 105228690Sdes if ((pame = pam_start(service, user, &pamc, &pamh)) != PAM_SUCCESS) 106228690Sdes pt_error(pame, "pam_start(%s)", service); 107228690Sdes return (pame); 108228690Sdes} 109228690Sdes 110228690Sdes/* 111228690Sdes * Wrapper for pam_authenticate(3) 112228690Sdes */ 113228690Sdesstatic int 114228690Sdespt_authenticate(int flags) 115228690Sdes{ 116228690Sdes int pame; 117228690Sdes 118228690Sdes flags |= silent; 119263421Sdes pt_verbose("pam_authenticate()"); 120228690Sdes if ((pame = pam_authenticate(pamh, flags)) != PAM_SUCCESS) 121228690Sdes pt_error(pame, "pam_authenticate()"); 122228690Sdes return (pame); 123228690Sdes} 124228690Sdes 125228690Sdes/* 126228690Sdes * Wrapper for pam_acct_mgmt(3) 127228690Sdes */ 128228690Sdesstatic int 129228690Sdespt_acct_mgmt(int flags) 130228690Sdes{ 131228690Sdes int pame; 132228690Sdes 133228690Sdes flags |= silent; 134263421Sdes pt_verbose("pam_acct_mgmt()"); 135228690Sdes if ((pame = pam_acct_mgmt(pamh, flags)) != PAM_SUCCESS) 136228690Sdes pt_error(pame, "pam_acct_mgmt()"); 137228690Sdes return (pame); 138228690Sdes} 139228690Sdes 140228690Sdes/* 141228690Sdes * Wrapper for pam_chauthtok(3) 142228690Sdes */ 143228690Sdesstatic int 144228690Sdespt_chauthtok(int flags) 145228690Sdes{ 146228690Sdes int pame; 147228690Sdes 148228690Sdes flags |= silent; 149263421Sdes pt_verbose("pam_chauthtok()"); 150228690Sdes if ((pame = pam_chauthtok(pamh, flags)) != PAM_SUCCESS) 151228690Sdes pt_error(pame, "pam_chauthtok()"); 152228690Sdes return (pame); 153228690Sdes} 154228690Sdes 155228690Sdes/* 156228690Sdes * Wrapper for pam_setcred(3) 157228690Sdes */ 158228690Sdesstatic int 159228690Sdespt_setcred(int flags) 160228690Sdes{ 161228690Sdes int pame; 162228690Sdes 163228690Sdes flags |= silent; 164263421Sdes pt_verbose("pam_setcred()"); 165228690Sdes if ((pame = pam_setcred(pamh, flags)) != PAM_SUCCESS) 166228690Sdes pt_error(pame, "pam_setcred()"); 167228690Sdes return (pame); 168228690Sdes} 169228690Sdes 170228690Sdes/* 171228690Sdes * Wrapper for pam_open_session(3) 172228690Sdes */ 173228690Sdesstatic int 174228690Sdespt_open_session(int flags) 175228690Sdes{ 176228690Sdes int pame; 177228690Sdes 178228690Sdes flags |= silent; 179263421Sdes pt_verbose("pam_open_session()"); 180228690Sdes if ((pame = pam_open_session(pamh, flags)) != PAM_SUCCESS) 181228690Sdes pt_error(pame, "pam_open_session()"); 182228690Sdes return (pame); 183228690Sdes} 184228690Sdes 185228690Sdes/* 186228690Sdes * Wrapper for pam_close_session(3) 187228690Sdes */ 188228690Sdesstatic int 189228690Sdespt_close_session(int flags) 190228690Sdes{ 191228690Sdes int pame; 192228690Sdes 193228690Sdes flags |= silent; 194263421Sdes pt_verbose("pam_close_session()"); 195228690Sdes if ((pame = pam_close_session(pamh, flags)) != PAM_SUCCESS) 196228690Sdes pt_error(pame, "pam_close_session()"); 197228690Sdes return (pame); 198228690Sdes} 199228690Sdes 200228690Sdes/* 201228690Sdes * Wrapper for pam_set_item(3) 202228690Sdes */ 203228690Sdesstatic int 204228690Sdespt_set_item(int item, const char *p) 205228690Sdes{ 206228690Sdes int pame; 207228690Sdes 208228690Sdes switch (item) { 209228690Sdes case PAM_SERVICE: 210228690Sdes case PAM_USER: 211228690Sdes case PAM_AUTHTOK: 212228690Sdes case PAM_OLDAUTHTOK: 213228690Sdes case PAM_TTY: 214228690Sdes case PAM_RHOST: 215228690Sdes case PAM_RUSER: 216228690Sdes case PAM_USER_PROMPT: 217228690Sdes case PAM_AUTHTOK_PROMPT: 218228690Sdes case PAM_OLDAUTHTOK_PROMPT: 219228690Sdes case PAM_HOST: 220228690Sdes pt_verbose("setting %s to %s", pam_item_name[item], p); 221228690Sdes break; 222228690Sdes default: 223228690Sdes pt_verbose("setting %s", pam_item_name[item]); 224228690Sdes break; 225228690Sdes } 226228690Sdes if ((pame = pam_set_item(pamh, item, p)) != PAM_SUCCESS) 227228690Sdes pt_error(pame, "pam_set_item(%s)", pam_item_name[item]); 228228690Sdes return (pame); 229228690Sdes} 230228690Sdes 231228690Sdes/* 232228690Sdes * Wrapper for pam_end(3) 233228690Sdes */ 234228690Sdesstatic int 235228690Sdespt_end(int pame) 236228690Sdes{ 237228690Sdes 238228690Sdes if (pamh != NULL && (pame = pam_end(pamh, pame)) != PAM_SUCCESS) 239228690Sdes /* can't happen */ 240228690Sdes pt_error(pame, "pam_end()"); 241228690Sdes return (pame); 242228690Sdes} 243228690Sdes 244228690Sdes/* 245228690Sdes * Retrieve and list the PAM environment variables 246228690Sdes */ 247228690Sdesstatic int 248228690Sdespt_listenv(void) 249228690Sdes{ 250228690Sdes char **pam_envlist, **pam_env; 251228690Sdes 252228690Sdes if ((pam_envlist = pam_getenvlist(pamh)) == NULL || 253228690Sdes *pam_envlist == NULL) { 254228690Sdes pt_verbose("no environment variables."); 255228690Sdes } else { 256228690Sdes pt_verbose("environment variables:"); 257228690Sdes for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) { 258228690Sdes printf(" %s\n", *pam_env); 259228690Sdes free(*pam_env); 260228690Sdes } 261228690Sdes } 262228690Sdes free(pam_envlist); 263228690Sdes return (PAM_SUCCESS); 264228690Sdes} 265228690Sdes 266228690Sdes/* 267228690Sdes * Print usage string and exit 268228690Sdes */ 269228690Sdesstatic void 270228690Sdesusage(void) 271228690Sdes{ 272228690Sdes 273247568Sdes fprintf(stderr, "usage: pamtest %s service command ...\n", 274247568Sdes "[-dkMPsv] [-H rhost] [-h host] [-t tty] [-U ruser] [-u user]"); 275228690Sdes exit(1); 276228690Sdes} 277228690Sdes 278228690Sdes/* 279263421Sdes * Handle an option that takes an int argument and can be used only once 280263421Sdes */ 281263421Sdesstatic void 282263421Sdesopt_num_once(int opt, long *num, const char *arg) 283263421Sdes{ 284263421Sdes char *end; 285263421Sdes long l; 286263421Sdes 287263421Sdes l = strtol(arg, &end, 0); 288263421Sdes if (end == optarg || *end != '\0') { 289263421Sdes fprintf(stderr, 290263421Sdes "The -%c option expects a numeric argument\n", opt); 291263421Sdes usage(); 292263421Sdes } 293263421Sdes *num = l; 294263421Sdes} 295263421Sdes 296263421Sdes/* 297228690Sdes * Handle an option that takes a string argument and can be used only once 298228690Sdes */ 299228690Sdesstatic void 300228690Sdesopt_str_once(int opt, const char **p, const char *arg) 301228690Sdes{ 302228690Sdes 303228690Sdes if (*p != NULL) { 304228690Sdes fprintf(stderr, "The -%c option can only be used once\n", opt); 305228690Sdes usage(); 306228690Sdes } 307228690Sdes *p = arg; 308228690Sdes} 309228690Sdes 310228690Sdes/* 311228690Sdes * Entry point 312228690Sdes */ 313228690Sdesint 314228690Sdesmain(int argc, char *argv[]) 315228690Sdes{ 316228690Sdes char hostname[1024]; 317228690Sdes const char *rhost = NULL; 318228690Sdes const char *host = NULL; 319228690Sdes const char *ruser = NULL; 320228690Sdes const char *user = NULL; 321228690Sdes const char *service = NULL; 322228690Sdes const char *tty = NULL; 323263421Sdes long timeout = 0; 324228690Sdes int keepatit = 0; 325228690Sdes int pame; 326228690Sdes int opt; 327228690Sdes 328263421Sdes while ((opt = getopt(argc, argv, "dH:h:kMPsT:t:U:u:v")) != -1) 329228690Sdes switch (opt) { 330228690Sdes case 'd': 331228690Sdes openpam_debug++; 332228690Sdes break; 333228690Sdes case 'H': 334228690Sdes opt_str_once(opt, &rhost, optarg); 335228690Sdes break; 336228690Sdes case 'h': 337228690Sdes opt_str_once(opt, &host, optarg); 338228690Sdes break; 339228690Sdes case 'k': 340228690Sdes keepatit = 1; 341228690Sdes break; 342247568Sdes case 'M': 343247568Sdes openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0); 344247568Sdes openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0); 345247568Sdes break; 346247568Sdes case 'P': 347247568Sdes openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0); 348247568Sdes openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0); 349247568Sdes break; 350228690Sdes case 's': 351228690Sdes silent = PAM_SILENT; 352228690Sdes break; 353263421Sdes case 'T': 354263421Sdes opt_num_once(opt, &timeout, optarg); 355263421Sdes if (timeout < 0 || timeout > INT_MAX) { 356263421Sdes fprintf(stderr, 357263421Sdes "Invalid conversation timeout\n"); 358263421Sdes usage(); 359263421Sdes } 360263421Sdes openpam_ttyconv_timeout = (int)timeout; 361263421Sdes break; 362228690Sdes case 't': 363228690Sdes opt_str_once(opt, &tty, optarg); 364228690Sdes break; 365228690Sdes case 'U': 366228690Sdes opt_str_once(opt, &ruser, optarg); 367228690Sdes break; 368228690Sdes case 'u': 369228690Sdes opt_str_once(opt, &user, optarg); 370228690Sdes break; 371228690Sdes case 'v': 372228690Sdes verbose++; 373228690Sdes break; 374228690Sdes default: 375228690Sdes usage(); 376228690Sdes } 377228690Sdes 378228690Sdes argc -= optind; 379228690Sdes argv += optind; 380228690Sdes 381228690Sdes if (argc < 1) 382228690Sdes usage(); 383228690Sdes 384228690Sdes service = *argv; 385228690Sdes --argc; 386228690Sdes ++argv; 387228690Sdes 388228690Sdes /* defaults */ 389263421Sdes if (service == NULL) 390263421Sdes service = "pamtest"; 391228690Sdes if (rhost == NULL) { 392228690Sdes if (gethostname(hostname, sizeof(hostname)) == -1) 393228690Sdes err(1, "gethostname()"); 394228690Sdes rhost = hostname; 395228690Sdes } 396228690Sdes if (tty == NULL) 397228690Sdes tty = ttyname(STDERR_FILENO); 398228690Sdes if (user == NULL) 399228690Sdes user = getlogin(); 400228690Sdes if (ruser == NULL) 401228690Sdes ruser = user; 402228690Sdes 403228690Sdes /* initialize PAM */ 404228690Sdes if ((pame = pt_start(service, user)) != PAM_SUCCESS) 405228690Sdes goto end; 406228690Sdes 407228690Sdes /* 408228690Sdes * pam_start(3) sets this to the machine's hostname, but we allow 409228690Sdes * the user to override it. 410228690Sdes */ 411228690Sdes if (host != NULL) 412228690Sdes if ((pame = pt_set_item(PAM_HOST, host)) != PAM_SUCCESS) 413228690Sdes goto end; 414228690Sdes 415228690Sdes /* 416228690Sdes * The remote host / user / tty are usually set by the 417228690Sdes * application. 418228690Sdes */ 419228690Sdes if ((pame = pt_set_item(PAM_RHOST, rhost)) != PAM_SUCCESS || 420228690Sdes (pame = pt_set_item(PAM_RUSER, ruser)) != PAM_SUCCESS || 421228690Sdes (pame = pt_set_item(PAM_TTY, tty)) != PAM_SUCCESS) 422228690Sdes goto end; 423228690Sdes 424228690Sdes while (argc > 0) { 425228690Sdes if (strcmp(*argv, "listenv") == 0 || 426228690Sdes strcmp(*argv, "env") == 0) { 427228690Sdes pame = pt_listenv(); 428228690Sdes } else if (strcmp(*argv, "authenticate") == 0 || 429228690Sdes strcmp(*argv, "auth") == 0) { 430228690Sdes pame = pt_authenticate(0); 431228690Sdes } else if (strcmp(*argv, "acct_mgmt") == 0 || 432228690Sdes strcmp(*argv, "account") == 0) { 433228690Sdes pame = pt_acct_mgmt(0); 434228690Sdes } else if (strcmp(*argv, "chauthtok") == 0 || 435228690Sdes strcmp(*argv, "change") == 0) { 436228690Sdes pame = pt_chauthtok(PAM_CHANGE_EXPIRED_AUTHTOK); 437228690Sdes } else if (strcmp(*argv, "forcechauthtok") == 0 || 438228690Sdes strcmp(*argv, "forcechange") == 0) { 439228690Sdes pame = pt_chauthtok(0); 440228690Sdes } else if (strcmp(*argv, "setcred") == 0 || 441228690Sdes strcmp(*argv, "establish_cred") == 0) { 442228690Sdes pame = pt_setcred(PAM_ESTABLISH_CRED); 443228690Sdes } else if (strcmp(*argv, "open_session") == 0 || 444228690Sdes strcmp(*argv, "open") == 0) { 445228690Sdes pame = pt_open_session(0); 446228690Sdes } else if (strcmp(*argv, "close_session") == 0 || 447228690Sdes strcmp(*argv, "close") == 0) { 448228690Sdes pame = pt_close_session(0); 449228690Sdes } else if (strcmp(*argv, "unsetcred") == 0 || 450228690Sdes strcmp(*argv, "delete_cred") == 0) { 451228690Sdes pame = pt_setcred(PAM_DELETE_CRED); 452228690Sdes } else { 453228690Sdes warnx("unknown primitive: %s", *argv); 454228690Sdes pame = PAM_SYSTEM_ERR; 455228690Sdes } 456228690Sdes if (pame != PAM_SUCCESS && !keepatit) { 457228690Sdes warnx("test aborted"); 458228690Sdes break; 459228690Sdes } 460228690Sdes --argc; 461228690Sdes ++argv; 462228690Sdes } 463228690Sdes 464228690Sdesend: 465228690Sdes (void)pt_end(pame); 466228690Sdes exit(pame == PAM_SUCCESS ? 0 : 1); 467228690Sdes} 468