194719Sdes/*- 294719Sdes * Copyright (c) 2002 Networks Associates Technologies, Inc. 394719Sdes * All rights reserved. 41590Srgrimes * 594719Sdes * This software was developed for the FreeBSD Project by ThinkSec AS and 694719Sdes * NAI Labs, the Security Research Division of Network Associates, Inc. 794719Sdes * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 894719Sdes * DARPA CHATS research program. 994719Sdes * 101590Srgrimes * Redistribution and use in source and binary forms, with or without 111590Srgrimes * modification, are permitted provided that the following conditions 121590Srgrimes * are met: 131590Srgrimes * 1. Redistributions of source code must retain the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer. 151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161590Srgrimes * notice, this list of conditions and the following disclaimer in the 171590Srgrimes * documentation and/or other materials provided with the distribution. 1894719Sdes * 3. The name of the author may not be used to endorse or promote 1994719Sdes * products derived from this software without specific prior written 2094719Sdes * permission. 211590Srgrimes * 2294719Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 231590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2594719Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 261590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321590Srgrimes * SUCH DAMAGE. 331590Srgrimes */ 341590Srgrimes 3595627Smarkm#include <sys/cdefs.h> 3695627Smarkm__FBSDID("$FreeBSD$"); 3795627Smarkm 3894719Sdes#include <sys/param.h> 391590Srgrimes 401590Srgrimes#include <err.h> 4194719Sdes#include <pwd.h> 421590Srgrimes#include <stdio.h> 4396384Sjedgar#include <stdlib.h> 44200462Sdelphij#include <syslog.h> 451590Srgrimes#include <unistd.h> 461590Srgrimes 4794719Sdes#include <security/pam_appl.h> 4894719Sdes#include <security/openpam.h> 496067Swpaul 5094719Sdesstatic pam_handle_t *pamh; 5194719Sdesstatic struct pam_conv pamc = { 5294719Sdes openpam_ttyconv, 5394719Sdes NULL 5494719Sdes}; 555752Swollman 5694719Sdesstatic char *yp_domain; 5794719Sdesstatic char *yp_host; 581590Srgrimes 5994719Sdesstatic void 6094719Sdesusage(void) 6194719Sdes{ 6295258Sdes fprintf(stderr, "usage: passwd [-ly] [-d domain] [-h host] [user]\n"); 6394719Sdes exit(1); 6494719Sdes} 651590Srgrimes 661590Srgrimesint 6794719Sdesmain(int argc, char *argv[]) 681590Srgrimes{ 6994719Sdes char hostname[MAXHOSTNAMELEN]; 70201385Sed struct passwd *pwd = NULL; /* Keep compiler happy. */ 7194719Sdes int o, pam_err; 7294719Sdes uid_t uid; 731590Srgrimes 7494719Sdes while ((o = getopt(argc, argv, "d:h:loy")) != -1) 7594719Sdes switch (o) { 7694719Sdes case 'd': 7794719Sdes yp_domain = optarg; 781590Srgrimes break; 7994719Sdes case 'h': 8094719Sdes yp_host = optarg; 815752Swollman break; 8294719Sdes case 'l': 8314212Swpaul case 'o': 8494719Sdes case 'y': 8594719Sdes /* compatibility */ 8614212Swpaul break; 871590Srgrimes default: 881590Srgrimes usage(); 891590Srgrimes } 901590Srgrimes 911590Srgrimes argc -= optind; 921590Srgrimes argv += optind; 931590Srgrimes 9494719Sdes uid = getuid(); 951590Srgrimes 9694719Sdes switch (argc) { 971590Srgrimes case 0: 9894719Sdes if ((pwd = getpwuid(uid)) == NULL) 9994719Sdes errx(1, "who are you?"); 1001590Srgrimes break; 1011590Srgrimes case 1: 10294719Sdes if ((pwd = getpwnam(*argv)) == NULL) 10394719Sdes errx(1, "%s: no such user", *argv); 1041590Srgrimes break; 1051590Srgrimes default: 1061590Srgrimes usage(); 1071590Srgrimes } 1081590Srgrimes 10994719Sdes if (uid != 0 && uid != pwd->pw_uid) 11094719Sdes errx(1, "permission denied"); 1116067Swpaul 11294719Sdes /* check where the user's from */ 11394719Sdes switch (pwd->pw_fields & _PWF_SOURCE) { 11494719Sdes case _PWF_FILES: 11594719Sdes fprintf(stderr, "Changing local password for %s\n", 11694719Sdes pwd->pw_name); 11794719Sdes break; 11894719Sdes case _PWF_NIS: 11994719Sdes fprintf(stderr, "Changing NIS password for %s\n", 12094719Sdes pwd->pw_name); 12194719Sdes break; 12294719Sdes default: 123113693Snectar /* XXX: Green men ought to be supported via PAM. */ 124113693Snectar errx(1, 125113693Snectar "Sorry, `passwd' can only change passwords for local or NIS users."); 1265752Swollman } 1271590Srgrimes 12894719Sdes#define pam_check(func) do { \ 12994719Sdes if (pam_err != PAM_SUCCESS) { \ 13094719Sdes if (pam_err == PAM_AUTH_ERR || pam_err == PAM_PERM_DENIED || \ 13194719Sdes pam_err == PAM_AUTHTOK_RECOVERY_ERR) \ 13294719Sdes warnx("sorry"); \ 13394719Sdes else \ 13494719Sdes warnx("%s(): %s", func, pam_strerror(pamh, pam_err)); \ 13594719Sdes goto end; \ 13694719Sdes } \ 13794719Sdes} while (0) 1381590Srgrimes 13994719Sdes /* initialize PAM */ 14094719Sdes pam_err = pam_start("passwd", pwd->pw_name, &pamc, &pamh); 14194719Sdes pam_check("pam_start"); 14294719Sdes 14394719Sdes pam_err = pam_set_item(pamh, PAM_TTY, ttyname(STDERR_FILENO)); 14494719Sdes pam_check("pam_set_item"); 14594719Sdes gethostname(hostname, sizeof hostname); 14694719Sdes pam_err = pam_set_item(pamh, PAM_RHOST, hostname); 14794719Sdes pam_check("pam_set_item"); 14894719Sdes pam_err = pam_set_item(pamh, PAM_RUSER, getlogin()); 14994719Sdes pam_check("pam_set_item"); 15094719Sdes 15194719Sdes /* set YP domain and host */ 15294719Sdes pam_err = pam_set_data(pamh, "yp_domain", yp_domain, NULL); 15394719Sdes pam_check("pam_set_data"); 15494719Sdes pam_err = pam_set_data(pamh, "yp_server", yp_host, NULL); 15594719Sdes pam_check("pam_set_data"); 15694719Sdes 15794719Sdes /* set new password */ 15894719Sdes pam_err = pam_chauthtok(pamh, 0); 15994719Sdes pam_check("pam_chauthtok"); 16094719Sdes 16194719Sdes end: 16294719Sdes pam_end(pamh, pam_err); 16394719Sdes exit(pam_err == PAM_SUCCESS ? 0 : 1); 1641590Srgrimes} 165