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