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