1 1.7 rillig /* $NetBSD: pam_passwd.c,v 1.7 2021/09/10 21:52:18 rillig Exp $ */ 2 1.2 thorpej 3 1.1 christos /*- 4 1.1 christos * Copyright (c) 2002 Networks Associates Technologies, Inc. 5 1.1 christos * All rights reserved. 6 1.1 christos * 7 1.1 christos * This software was developed for the FreeBSD Project by ThinkSec AS and 8 1.1 christos * NAI Labs, the Security Research Division of Network Associates, Inc. 9 1.1 christos * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 10 1.1 christos * DARPA CHATS research program. 11 1.1 christos * 12 1.1 christos * Redistribution and use in source and binary forms, with or without 13 1.1 christos * modification, are permitted provided that the following conditions 14 1.1 christos * are met: 15 1.1 christos * 1. Redistributions of source code must retain the above copyright 16 1.1 christos * notice, this list of conditions and the following disclaimer. 17 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 christos * notice, this list of conditions and the following disclaimer in the 19 1.1 christos * documentation and/or other materials provided with the distribution. 20 1.1 christos * 3. The name of the author may not be used to endorse or promote 21 1.1 christos * products derived from this software without specific prior written 22 1.1 christos * permission. 23 1.1 christos * 24 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 1.1 christos * SUCH DAMAGE. 35 1.1 christos */ 36 1.1 christos 37 1.1 christos #include <sys/cdefs.h> 38 1.1 christos #ifdef __FreeBSD__ 39 1.1 christos __FBSDID("$FreeBSD: src/usr.bin/passwd/passwd.c,v 1.23 2003/04/18 21:27:09 nectar Exp $"); 40 1.1 christos #else 41 1.7 rillig __RCSID("$NetBSD: pam_passwd.c,v 1.7 2021/09/10 21:52:18 rillig Exp $"); 42 1.1 christos #endif 43 1.1 christos 44 1.1 christos #include <sys/param.h> 45 1.1 christos 46 1.1 christos #include <err.h> 47 1.1 christos #include <pwd.h> 48 1.1 christos #include <stdio.h> 49 1.1 christos #include <stdlib.h> 50 1.1 christos #include <syslog.h> 51 1.1 christos #include <unistd.h> 52 1.1 christos 53 1.1 christos #include "extern.h" 54 1.1 christos 55 1.1 christos #include <security/pam_appl.h> 56 1.1 christos #include <security/openpam.h> 57 1.1 christos 58 1.1 christos static pam_handle_t *pamh; 59 1.1 christos static struct pam_conv pamc = { 60 1.1 christos openpam_ttyconv, 61 1.1 christos NULL 62 1.1 christos }; 63 1.1 christos 64 1.3 thorpej #define pam_check(msg) \ 65 1.3 thorpej do { \ 66 1.3 thorpej if (pam_err != PAM_SUCCESS) { \ 67 1.3 thorpej warnx("%s: %s", (msg), pam_strerror(pamh, pam_err)); \ 68 1.3 thorpej goto end; \ 69 1.3 thorpej } \ 70 1.7 rillig } while (0) 71 1.1 christos 72 1.3 thorpej void 73 1.3 thorpej pwpam_process(const char *username, int argc, char **argv) 74 1.3 thorpej { 75 1.3 thorpej int ch, pam_err; 76 1.3 thorpej char hostname[MAXHOSTNAMELEN + 1]; 77 1.1 christos 78 1.5 gdt /* details about the invoking user for logging */ 79 1.5 gdt const uid_t i_uid = getuid(); 80 1.5 gdt const struct passwd *const i_pwd = getpwuid(i_uid); 81 1.5 gdt const char *const i_username = (i_pwd && i_pwd->pw_name) 82 1.5 gdt ? i_pwd->pw_name : "(null)"; 83 1.5 gdt 84 1.3 thorpej while ((ch = getopt(argc, argv, "")) != -1) { 85 1.3 thorpej switch (ch) { 86 1.3 thorpej default: 87 1.3 thorpej usage(); 88 1.3 thorpej /* NOTREACHED */ 89 1.3 thorpej } 90 1.3 thorpej } 91 1.3 thorpej 92 1.3 thorpej argc -= optind; 93 1.3 thorpej argv += optind; 94 1.1 christos 95 1.3 thorpej switch (argc) { 96 1.3 thorpej case 0: 97 1.3 thorpej /* username already provided */ 98 1.1 christos break; 99 1.3 thorpej case 1: 100 1.3 thorpej username = argv[0]; 101 1.1 christos break; 102 1.1 christos default: 103 1.3 thorpej usage(); 104 1.3 thorpej /* NOTREACHED */ 105 1.1 christos } 106 1.1 christos 107 1.4 jnemeth (void)printf("Changing password for %s.\n", username); 108 1.4 jnemeth 109 1.3 thorpej /* initialize PAM -- always use the program name "passwd" */ 110 1.3 thorpej pam_err = pam_start("passwd", username, &pamc, &pamh); 111 1.6 joerg if (pam_err != PAM_SUCCESS) 112 1.6 joerg errx(1, "unable to start PAM session: %s", 113 1.6 joerg pam_strerror(NULL, pam_err)); 114 1.1 christos 115 1.3 thorpej pam_err = pam_set_item(pamh, PAM_TTY, ttyname(STDERR_FILENO)); 116 1.3 thorpej pam_check("unable to set TTY"); 117 1.1 christos 118 1.1 christos (void)gethostname(hostname, sizeof hostname); 119 1.1 christos pam_err = pam_set_item(pamh, PAM_RHOST, hostname); 120 1.3 thorpej pam_check("unable to set RHOST"); 121 1.3 thorpej 122 1.1 christos pam_err = pam_set_item(pamh, PAM_RUSER, getlogin()); 123 1.3 thorpej pam_check("unable to set RUSER"); 124 1.1 christos 125 1.1 christos /* set new password */ 126 1.1 christos pam_err = pam_chauthtok(pamh, 0); 127 1.5 gdt if (pam_err != PAM_SUCCESS) { 128 1.5 gdt if (pam_err == PAM_PERM_DENIED) { 129 1.5 gdt syslog(LOG_AUTH | LOG_NOTICE, 130 1.5 gdt "user %s (UID %lu) failed to change the " 131 1.5 gdt "PAM authentication token of user %s: %s", 132 1.5 gdt i_username, (unsigned long)i_uid, username, 133 1.5 gdt pam_strerror(pamh, pam_err)); 134 1.5 gdt } 135 1.3 thorpej printf("Unable to change auth token: %s\n", 136 1.3 thorpej pam_strerror(pamh, pam_err)); 137 1.5 gdt } else { 138 1.5 gdt syslog(LOG_AUTH | LOG_INFO, 139 1.5 gdt "user %s (UID %lu) successfully changed the " 140 1.5 gdt "PAM authentication token of user %s", 141 1.5 gdt i_username, (unsigned long)i_uid, username); 142 1.5 gdt } 143 1.1 christos 144 1.1 christos end: 145 1.1 christos pam_end(pamh, pam_err); 146 1.3 thorpej if (pam_err == PAM_SUCCESS) 147 1.3 thorpej return; 148 1.3 thorpej exit(1); 149 1.1 christos } 150