login_chpass.c revision 1.18
1/* $OpenBSD: login_chpass.c,v 1.18 2015/10/22 12:32:33 tedu Exp $ */ 2 3/*- 4 * Copyright (c) 1995,1996 Berkeley Software Design, Inc. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Berkeley Software Design, 17 * Inc. 18 * 4. The name of Berkeley Software Design, Inc. may not be used to endorse 19 * or promote products derived from this software without specific prior 20 * written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * BSDI $From: login_chpass.c,v 1.3 1996/08/21 21:01:48 prb Exp $ 35 */ 36#include <sys/stat.h> 37#include <sys/time.h> 38#include <sys/resource.h> 39#include <sys/file.h> 40#include <sys/uio.h> 41#include <sys/wait.h> 42 43#include <err.h> 44#include <errno.h> 45#include <pwd.h> 46#include <signal.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <syslog.h> 51#include <unistd.h> 52#include <login_cap.h> 53 54#ifdef YP 55# include <netdb.h> 56# include <rpc/rpc.h> 57# include <rpcsvc/yp_prot.h> 58# include <rpcsvc/ypclnt.h> 59# define passwd yp_passwd_rec 60# include <rpcsvc/yppasswd.h> 61# undef passwd 62#endif 63 64#define _PATH_LOGIN_LCHPASS "/usr/libexec/auth/login_lchpass" 65 66#define BACK_CHANNEL 3 67 68#ifdef YP 69struct iovec iov[2] = { { BI_SILENT, sizeof(BI_SILENT) - 1 }, { "\n", 1 } }; 70 71int _yp_check(char **); 72char *ypgetnewpasswd(struct passwd *, char **); 73struct passwd *ypgetpwnam(char *); 74void kbintr(int); 75int pwd_gensalt(char *, int, login_cap_t *, char); 76#endif 77 78void local_chpass(char **); 79void yp_chpass(char *); 80 81int 82main(int argc, char *argv[]) 83{ 84#ifdef YP 85 char *username; 86#endif 87 struct rlimit rl; 88 int c; 89 90 rl.rlim_cur = 0; 91 rl.rlim_max = 0; 92 (void)setrlimit(RLIMIT_CORE, &rl); 93 94 (void)setpriority(PRIO_PROCESS, 0, 0); 95 96 openlog("login", LOG_ODELAY, LOG_AUTH); 97 98 while ((c = getopt(argc, argv, "s:v:")) != -1) 99 switch (c) { 100 case 'v': 101 break; 102 case 's': /* service */ 103 if (strcmp(optarg, "login") != 0) { 104 syslog(LOG_ERR, "%s: invalid service", optarg); 105 exit(1); 106 } 107 break; 108 default: 109 syslog(LOG_ERR, "usage error"); 110 exit(1); 111 } 112 113 switch (argc - optind) { 114 case 2: 115 /* class is not used */ 116 case 1: 117#ifdef YP 118 username = argv[optind]; 119#endif 120 break; 121 default: 122 syslog(LOG_ERR, "usage error"); 123 exit(1); 124 } 125 126#ifdef YP 127 if (_yp_check(NULL)) 128 yp_chpass(username); 129#endif 130 local_chpass(argv); 131 /* NOTREACHED */ 132 exit(0); 133} 134 135void 136local_chpass(char *argv[]) 137{ 138 139 /* login_lchpass doesn't check instance so don't bother restoring it */ 140 argv[0] = strrchr(_PATH_LOGIN_LCHPASS, '/') + 1; 141 execv(_PATH_LOGIN_LCHPASS, argv); 142 syslog(LOG_ERR, "%s: %m", _PATH_LOGIN_LCHPASS); 143 exit(1); 144} 145 146#ifdef YP 147void 148yp_chpass(char *username) 149{ 150 char *master; 151 int r, rpcport, status; 152 struct yppasswd yppasswd; 153 struct passwd *pw; 154 struct timeval tv; 155 CLIENT *client; 156 extern char *domain; 157 158 (void)signal(SIGINT, kbintr); 159 (void)signal(SIGQUIT, kbintr); 160 161 if ((r = yp_get_default_domain(&domain)) != 0) { 162 warnx("can't get local YP domain. Reason: %s", yperr_string(r)); 163 exit(1); 164 } 165 166 /* 167 * Find the host for the passwd map; it should be running 168 * the daemon. 169 */ 170 if ((r = yp_master(domain, "passwd.byname", &master)) != 0) { 171 warnx("can't find the master YP server. Reason: %s", 172 yperr_string(r)); 173 exit(1); 174 } 175 176 /* Ask the portmapper for the port of the daemon. */ 177 if ((rpcport = getrpcport(master, YPPASSWDPROG, 178 YPPASSWDPROC_UPDATE, IPPROTO_UDP)) == 0) { 179 warnx("master YP server not running yppasswd daemon."); 180 warnx("Can't change password."); 181 exit(1); 182 } 183 184 if (rpcport >= IPPORT_RESERVED) { 185 warnx("yppasswd daemon is on an invalid port."); 186 exit(1); 187 } 188 189 /* If user doesn't exist, just prompt for old password and exit. */ 190 pw = ypgetpwnam(username); 191 if (pw) { 192 if (pw->pw_uid == 0) { 193 syslog(LOG_ERR, "attempted root password change"); 194 pw = NULL; 195 } else if (*pw->pw_passwd == '\0') { 196 syslog(LOG_ERR, "%s attempting to add password", 197 username); 198 pw = NULL; 199 } 200 } 201 if (pw == NULL) { 202 char *p; 203 /* no such user, but fake to thwart timing attack */ 204 if ((p = getpass("Old password:")) != NULL) { 205 crypt_checkpass(p, NULL); 206 explicit_bzero(p, strlen(p)); 207 } 208 warnx("YP passwd database unchanged."); 209 exit(1); 210 } 211 212 /* prompt for new password */ 213 yppasswd.newpw.pw_passwd = ypgetnewpasswd(pw, &yppasswd.oldpass); 214 215 /* tell rpc.yppasswdd */ 216 yppasswd.newpw.pw_name = pw->pw_name; 217 yppasswd.newpw.pw_uid = pw->pw_uid; 218 yppasswd.newpw.pw_gid = pw->pw_gid; 219 yppasswd.newpw.pw_gecos = pw->pw_gecos; 220 yppasswd.newpw.pw_dir = pw->pw_dir; 221 yppasswd.newpw.pw_shell = pw->pw_shell; 222 223 client = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp"); 224 if (client == NULL) { 225 warnx("cannot contact yppasswdd on %s: Reason: %s", 226 master, yperr_string(YPERR_YPBIND)); 227 free(yppasswd.newpw.pw_passwd); 228 exit(1); 229 } 230 client->cl_auth = authunix_create_default(); 231 tv.tv_sec = 2; 232 tv.tv_usec = 0; 233 r = clnt_call(client, YPPASSWDPROC_UPDATE, 234 xdr_yppasswd, &yppasswd, xdr_int, &status, tv); 235 if (r) 236 warnx("rpc to yppasswdd failed."); 237 else if (status) { 238 printf("Couldn't change YP password.\n"); 239 free(yppasswd.newpw.pw_passwd); 240 exit(1); 241 } 242 printf("The YP password has been changed on %s, the master YP passwd server.\n", 243 master); 244 free(yppasswd.newpw.pw_passwd); 245 (void)writev(BACK_CHANNEL, iov, 2); 246 exit(0); 247} 248 249/* ARGSUSED */ 250void 251kbintr(int signo) 252{ 253 char msg[] = "YP passwd database unchanged.\n"; 254 struct iovec iv[3]; 255 extern char *__progname; 256 257 iv[0].iov_base = __progname; 258 iv[0].iov_len = strlen(__progname); 259 iv[1].iov_base = ": "; 260 iv[1].iov_len = 2; 261 iv[2].iov_base = msg; 262 iv[2].iov_len = sizeof(msg) - 1; 263 writev(STDERR_FILENO, iv, 3); 264 265 _exit(1); 266} 267#endif 268