1 /* $OpenBSD: login_chpass.c,v 1.2 2001/10/24 13:06:35 mpech 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/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 #ifdef KERBEROS 65 # include <netinet/in.h> 66 # include <kerberosIV/krb.h> 67 # include <kerberosIV/kadm.h> 68 # include <kerberosIV/kadm_err.h> 69 #endif 70 71 #define _PATH_LOGIN_LCHPASS "/usr/libexec/auth/login_lchpass" 72 73 #ifdef YP 74 int _yp_check __P((char **)); 75 char *ypgetnewpasswd __P((struct passwd *, char **)); 76 struct passwd *ypgetpwnam __P((char *)); 77 #endif 78 79 #ifdef KERBEROS 80 int get_pw_new_pwd __P((char *, int, krb_principal *, int)); 81 char realm[REALM_SZ]; 82 #endif 83 84 void local_chpass __P((char **)); 85 void krb_chpass __P((char *, char *, char **)); 86 void yp_chpass __P((char *)); 87 88 int 89 main(argc, argv) 90 int argc; 91 char *argv[]; 92 { 93 struct rlimit rl; 94 char *username; 95 char *instance; 96 int c; 97 98 rl.rlim_cur = 0; 99 rl.rlim_max = 0; 100 (void)setrlimit(RLIMIT_CORE, &rl); 101 102 (void)signal(SIGQUIT, SIG_IGN); 103 (void)signal(SIGINT, SIG_IGN); 104 (void)setpriority(PRIO_PROCESS, 0, 0); 105 106 openlog("login", LOG_ODELAY, LOG_AUTH); 107 108 while ((c = getopt(argc, argv, "s:v:")) != -1) 109 switch(c) { 110 case 'v': 111 break; 112 case 's': /* service */ 113 if (strcmp(optarg, "login") != 0) { 114 syslog(LOG_ERR, "%s: invalid service", optarg); 115 exit(1); 116 } 117 break; 118 default: 119 syslog(LOG_ERR, "usage error"); 120 exit(1); 121 } 122 123 switch(argc - optind) { 124 case 2: 125 /* class is not used */ 126 case 1: 127 username = argv[optind]; 128 break; 129 default: 130 syslog(LOG_ERR, "usage error"); 131 exit(1); 132 } 133 134 /* Instance ignored for all but Kerberos. */ 135 instance = strchr(username, '.'); 136 if (instance) 137 *instance++ = '\0'; 138 else 139 instance = ""; 140 141 #ifdef KERBEROS 142 if (krb_get_lrealm(realm, 0) == KSUCCESS) 143 krb_chpass(username, instance, argv); 144 #endif 145 #ifdef YP 146 if (_yp_check(NULL)) 147 yp_chpass(username); 148 #endif 149 local_chpass(argv); 150 /* NOTREACHED */ 151 exit(0); 152 } 153 154 void 155 local_chpass(argv) 156 char *argv[]; 157 { 158 159 /* login_lchpass doesn't check instance so don't bother restoring it */ 160 argv[0] = strrchr(_PATH_LOGIN_LCHPASS, '/') + 1; 161 execv(_PATH_LOGIN_LCHPASS, argv); 162 syslog(LOG_ERR, "%s: %m", _PATH_LOGIN_LCHPASS); 163 exit(1); 164 } 165 166 #ifdef YP 167 void 168 yp_chpass(username) 169 char *username; 170 { 171 FILE *back; 172 char *master; 173 int r, rpcport, status; 174 struct yppasswd yppasswd; 175 struct passwd *pw; 176 struct timeval tv; 177 CLIENT *client; 178 extern char *domain; 179 180 if (!(back = fdopen(3, "a"))) { 181 syslog(LOG_ERR, "reopening back channel: %m"); 182 exit(1); 183 } 184 185 if ((r = yp_get_default_domain(&domain)) != 0) { 186 warnx("can't get local YP domain. Reason: %s", yperr_string(r)); 187 exit(1); 188 } 189 190 /* 191 * Find the host for the passwd map; it should be running 192 * the daemon. 193 */ 194 if ((r = yp_master(domain, "passwd.byname", &master)) != 0) { 195 warnx("can't find the master YP server. Reason: %s", 196 yperr_string(r)); 197 exit(1); 198 } 199 200 /* Ask the portmapper for the port of the daemon. */ 201 if ((rpcport = getrpcport(master, YPPASSWDPROG, 202 YPPASSWDPROC_UPDATE, IPPROTO_UDP)) == 0) { 203 warnx("master YP server not running yppasswd daemon."); 204 warnx("Can't change password."); 205 exit(1); 206 } 207 208 if (rpcport >= IPPORT_RESERVED) { 209 warnx("yppasswd daemon is on an invalid port."); 210 exit(1); 211 } 212 213 /* If user doesn't exist, just prompt for old password and exit. */ 214 if ((pw = ypgetpwnam(username)) == NULL) { 215 char *p = getpass("Old password:"); 216 crypt(p, "xx"); 217 memset(p, 0, strlen(p)); 218 warnx("YP passwd database unchanged."); 219 exit(1); 220 } 221 222 if (*pw->pw_passwd == '\0') { 223 syslog(LOG_ERR, "%s attempting to add password", username); 224 fprintf(back, BI_SILENT "\n"); 225 exit(0); 226 } 227 228 /* prompt for new password */ 229 yppasswd.newpw.pw_passwd = ypgetnewpasswd(pw, &yppasswd.oldpass); 230 231 /* tell rpc.yppasswdd */ 232 yppasswd.newpw.pw_name = pw->pw_name; 233 yppasswd.newpw.pw_uid = pw->pw_uid; 234 yppasswd.newpw.pw_gid = pw->pw_gid; 235 yppasswd.newpw.pw_gecos = pw->pw_gecos; 236 yppasswd.newpw.pw_dir = pw->pw_dir; 237 yppasswd.newpw.pw_shell = pw->pw_shell; 238 239 client = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp"); 240 if (client == NULL) { 241 warnx("cannot contact yppasswdd on %s: Reason: %s", 242 master, yperr_string(YPERR_YPBIND)); 243 free(yppasswd.newpw.pw_passwd); 244 exit(1); 245 } 246 client->cl_auth = authunix_create_default(); 247 tv.tv_sec = 2; 248 tv.tv_usec = 0; 249 r = clnt_call(client, YPPASSWDPROC_UPDATE, 250 xdr_yppasswd, &yppasswd, xdr_int, &status, tv); 251 if (r) 252 warnx("rpc to yppasswdd failed."); 253 else if (status) { 254 printf("Couldn't change YP password.\n"); 255 free(yppasswd.newpw.pw_passwd); 256 exit(1); 257 } 258 printf("The YP password has been changed on %s, the master YP passwd server.\n", 259 master); 260 free(yppasswd.newpw.pw_passwd); 261 fprintf(back, BI_SILENT "\n"); 262 exit(0); 263 } 264 #endif 265 266 #ifdef KERBEROS 267 void 268 krb_chpass(username, instance, argv) 269 char *username; 270 char *instance; 271 char *argv[]; 272 { 273 FILE *back; 274 int rval; 275 char pword[MAX_KPW_LEN]; 276 char tktstring[MAXPATHLEN]; 277 krb_principal principal; 278 279 if (!(back = fdopen(3, "a"))) { 280 syslog(LOG_ERR, "reopening back channel: %m"); 281 exit(1); 282 } 283 284 memset(&principal, 0, sizeof(principal)); 285 krb_get_default_principal(principal.name, 286 principal.instance, principal.realm); 287 288 snprintf(tktstring, sizeof(tktstring), "%s.chpass.%s.%d", 289 TKT_ROOT, username, getpid()); 290 krb_set_tkt_string(tktstring); 291 292 (void)setpriority(PRIO_PROCESS, 0, -4); 293 294 if (get_pw_new_pwd(pword, sizeof(pword), &principal, 0)) { 295 dest_tkt(); 296 exit(1); 297 } 298 299 rval = kadm_init_link (PWSERV_NAME, KRB_MASTER, principal.realm); 300 if (rval != KADM_SUCCESS) 301 com_err(argv[0], rval, "while initializing"); 302 else { 303 des_cblock newkey; 304 char *pw_msg; /* message from server */ 305 306 des_string_to_key(pword, &newkey); 307 rval = kadm_change_pw_plain((u_char *)&newkey, pword, &pw_msg); 308 memset(newkey, 0, sizeof(newkey)); 309 310 if (rval == KADM_INSECURE_PW) 311 warnx("Insecure password: %s", pw_msg); 312 else if (rval != KADM_SUCCESS) 313 com_err(argv[0], rval, "attempting to change password."); 314 } 315 memset(pword, 0, sizeof(pword)); 316 317 if (rval != KADM_SUCCESS) 318 fprintf(stderr, "Password NOT changed.\n"); 319 else 320 printf("Password changed.\n"); 321 322 dest_tkt(); 323 324 if (rval == 0) 325 fprintf(back, BI_SILENT "\n"); 326 exit(rval); 327 } 328 #endif 329