login_chpass.c revision 1.13
1/* $OpenBSD: login_chpass.c,v 1.13 2004/09/28 21:52:40 deraadt 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/param.h> 37#include <sys/stat.h> 38#include <sys/time.h> 39#include <sys/resource.h> 40#include <sys/file.h> 41#include <sys/uio.h> 42#include <sys/wait.h> 43 44#include <err.h> 45#include <errno.h> 46#include <pwd.h> 47#include <signal.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#include <syslog.h> 52#include <unistd.h> 53#include <login_cap.h> 54 55#ifdef YP 56# include <netdb.h> 57# include <rpc/rpc.h> 58# include <rpcsvc/yp_prot.h> 59# include <rpcsvc/ypclnt.h> 60# define passwd yp_passwd_rec 61# include <rpcsvc/yppasswd.h> 62# undef passwd 63#endif 64 65#define _PATH_LOGIN_LCHPASS "/usr/libexec/auth/login_lchpass" 66 67#define BACK_CHANNEL 3 68 69#ifdef YP 70struct iovec iov[2] = { { BI_SILENT, sizeof(BI_SILENT) - 1 }, { "\n", 1 } }; 71 72int _yp_check(char **); 73char *ypgetnewpasswd(struct passwd *, char **); 74struct passwd *ypgetpwnam(char *); 75void kbintr(int); 76#endif 77 78void local_chpass(char **); 79void krb_chpass(char *, char *, char **); 80void yp_chpass(char *); 81 82int 83main(int argc, char *argv[]) 84{ 85#ifdef YP 86 char *username; 87#endif 88 struct rlimit rl; 89 int c; 90 91 rl.rlim_cur = 0; 92 rl.rlim_max = 0; 93 (void)setrlimit(RLIMIT_CORE, &rl); 94 95 (void)setpriority(PRIO_PROCESS, 0, 0); 96 97 openlog("login", LOG_ODELAY, LOG_AUTH); 98 99 while ((c = getopt(argc, argv, "s:v:")) != -1) 100 switch (c) { 101 case 'v': 102 break; 103 case 's': /* service */ 104 if (strcmp(optarg, "login") != 0) { 105 syslog(LOG_ERR, "%s: invalid service", optarg); 106 exit(1); 107 } 108 break; 109 default: 110 syslog(LOG_ERR, "usage error"); 111 exit(1); 112 } 113 114 switch (argc - optind) { 115 case 2: 116 /* class is not used */ 117 case 1: 118#ifdef YP 119 username = argv[optind]; 120#endif 121 break; 122 default: 123 syslog(LOG_ERR, "usage error"); 124 exit(1); 125 } 126 127#ifdef YP 128 if (_yp_check(NULL)) 129 yp_chpass(username); 130#endif 131 local_chpass(argv); 132 /* NOTREACHED */ 133 exit(0); 134} 135 136void 137local_chpass(char *argv[]) 138{ 139 140 /* login_lchpass doesn't check instance so don't bother restoring it */ 141 argv[0] = strrchr(_PATH_LOGIN_LCHPASS, '/') + 1; 142 execv(_PATH_LOGIN_LCHPASS, argv); 143 syslog(LOG_ERR, "%s: %m", _PATH_LOGIN_LCHPASS); 144 exit(1); 145} 146 147#ifdef YP 148void 149yp_chpass(char *username) 150{ 151 char *master; 152 int r, rpcport, status; 153 struct yppasswd yppasswd; 154 struct passwd *pw; 155 struct timeval tv; 156 CLIENT *client; 157 extern char *domain; 158 159 (void)signal(SIGINT, kbintr); 160 (void)signal(SIGQUIT, kbintr); 161 162 if ((r = yp_get_default_domain(&domain)) != 0) { 163 warnx("can't get local YP domain. Reason: %s", yperr_string(r)); 164 exit(1); 165 } 166 167 /* 168 * Find the host for the passwd map; it should be running 169 * the daemon. 170 */ 171 if ((r = yp_master(domain, "passwd.byname", &master)) != 0) { 172 warnx("can't find the master YP server. Reason: %s", 173 yperr_string(r)); 174 exit(1); 175 } 176 177 /* Ask the portmapper for the port of the daemon. */ 178 if ((rpcport = getrpcport(master, YPPASSWDPROG, 179 YPPASSWDPROC_UPDATE, IPPROTO_UDP)) == 0) { 180 warnx("master YP server not running yppasswd daemon."); 181 warnx("Can't change password."); 182 exit(1); 183 } 184 185 if (rpcport >= IPPORT_RESERVED) { 186 warnx("yppasswd daemon is on an invalid port."); 187 exit(1); 188 } 189 190 /* If user doesn't exist, just prompt for old password and exit. */ 191 pw = ypgetpwnam(username); 192 if (pw) { 193 if (pw->pw_uid == 0) { 194 syslog(LOG_ERR, "attempted root password change"); 195 pw = NULL; 196 } else if (*pw->pw_passwd == '\0') { 197 syslog(LOG_ERR, "%s attempting to add password", 198 username); 199 pw = NULL; 200 } 201 } 202 if (pw == NULL) { 203 char *p = getpass("Old password:"); 204 if (p != NULL) { 205 crypt(p, "xx"); 206 memset(p, 0, 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