xref: /openbsd-src/lib/libutil/check_expire.c (revision b7041c0781c8668129da8084451ded41b0c43954)
1*b7041c07Sderaadt /*	$OpenBSD: check_expire.c,v 1.14 2021/10/24 21:24:20 deraadt Exp $	*/
2acc2517fSmillert 
3acc2517fSmillert /*
4acc2517fSmillert  * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
5acc2517fSmillert  *
6acc2517fSmillert  * Redistribution and use in source and binary forms, with or without
7acc2517fSmillert  * modification, are permitted provided that the following conditions
8acc2517fSmillert  * are met:
9acc2517fSmillert  * 1. Redistributions of source code must retain the above copyright
10acc2517fSmillert  *    notice, this list of conditions and the following disclaimer.
11acc2517fSmillert  * 2. Redistributions in binary form must reproduce the above copyright
12acc2517fSmillert  *    notice, this list of conditions and the following disclaimer in the
13acc2517fSmillert  *    documentation and/or other materials provided with the distribution.
14acc2517fSmillert  * 3. All advertising materials mentioning features or use of this software
15acc2517fSmillert  *    must display the following acknowledgement:
16acc2517fSmillert  *	This product includes software developed by Berkeley Software Design,
17acc2517fSmillert  *	Inc.
18acc2517fSmillert  * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
19acc2517fSmillert  *    or promote products derived from this software without specific prior
20acc2517fSmillert  *    written permission.
21acc2517fSmillert  *
22acc2517fSmillert  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
23acc2517fSmillert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24acc2517fSmillert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25acc2517fSmillert  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
26acc2517fSmillert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27acc2517fSmillert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28acc2517fSmillert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29acc2517fSmillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30acc2517fSmillert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31acc2517fSmillert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32acc2517fSmillert  * SUCH DAMAGE.
33acc2517fSmillert  *
34acc2517fSmillert  *	BSDI $From: check_expire.c,v 2.1 1997/08/08 18:38:25 prb Exp $
35acc2517fSmillert  */
36acc2517fSmillert 
37acc2517fSmillert #include <sys/types.h>
38acc2517fSmillert 
39acc2517fSmillert #include <errno.h>
40acc2517fSmillert #include <fcntl.h>
41acc2517fSmillert #include <pwd.h>
42acc2517fSmillert #include <signal.h>
43acc2517fSmillert #include <stdio.h>
44acc2517fSmillert #include <stdlib.h>
45acc2517fSmillert #include <string.h>
46acc2517fSmillert #include <time.h>
47acc2517fSmillert #include <login_cap.h>
48acc2517fSmillert #include <bsd_auth.h>
49acc2517fSmillert 
5079822b59Smillert #include "util.h"
5179822b59Smillert 
529a60272cSmillert static char *pwd_update(const struct passwd *, const struct passwd *);
53acc2517fSmillert 
54f7055df5Smillert #define SECSPERDAY	(24 * 60 * 60)
55f7055df5Smillert #define TWOWEEKS	(2 * 7 * SECSPERDAY)
56f7055df5Smillert 
57acc2517fSmillert int
login_check_expire(FILE * back,struct passwd * pwd,char * class,int lastchance)589a60272cSmillert login_check_expire(FILE *back, struct passwd *pwd, char *class, int lastchance)
59acc2517fSmillert {
60acc2517fSmillert 	auth_session_t *as;
61acc2517fSmillert 	login_cap_t *lc;
62acc2517fSmillert 	quad_t dead, expire, warn;
63acc2517fSmillert 	char *p;
64acc2517fSmillert 
65acc2517fSmillert 	if ((as = auth_open()) == NULL) {
661e50994aSmillert 		fprintf(back, BI_VALUE
671e50994aSmillert 		    " errormsg Unable to create auth session\n");
681e50994aSmillert 		fprintf(back, BI_REJECT "\n");
69acc2517fSmillert 		return (1);
70acc2517fSmillert 	}
71acc2517fSmillert 	if (auth_setpwd(as, pwd) < 0) {
721e50994aSmillert 		fprintf(back, BI_VALUE
731e50994aSmillert 		    " errormsg Unable to set pwd entry in auth session\n");
741e50994aSmillert 		fprintf(back, BI_REJECT "\n");
75acc2517fSmillert 		return (1);
76acc2517fSmillert 	}
77acc2517fSmillert 
78acc2517fSmillert 	expire = auth_check_change(as);
79acc2517fSmillert 	auth_close(as);
80acc2517fSmillert 
81acc2517fSmillert 	if (expire != 0) {
82acc2517fSmillert 		fprintf(back, BI_VALUE " expire %qd\n", expire);
83acc2517fSmillert 
84acc2517fSmillert 		if (class == NULL)
85acc2517fSmillert 			class = pwd->pw_class;
86acc2517fSmillert 
87acc2517fSmillert 		if ((lc = login_getclass(class)) == NULL) {
88acc2517fSmillert 			dead = 0;
89acc2517fSmillert 			warn = 0;
90acc2517fSmillert 		} else {
91acc2517fSmillert 			dead = login_getcaptime(lc, "password-dead", 0, 0);
92acc2517fSmillert 			warn = login_getcaptime(lc, "password-warn",
93f7055df5Smillert 			    TWOWEEKS, TWOWEEKS);
941e50994aSmillert 			if (dead < 0)
95acc2517fSmillert 				dead = 0;
961e50994aSmillert 			if (warn < 0)
97acc2517fSmillert 				warn = 0;
98acc2517fSmillert 		}
99a7d05627Smpech 		login_close(lc);
100acc2517fSmillert 
101acc2517fSmillert 		/*
102acc2517fSmillert 		 * If their password is dead (expired longer than
103acc2517fSmillert 		 * password-dead) then just reject them.  If it is
104acc2517fSmillert 		 * expired but not dead yet, reject them with a
105acc2517fSmillert 		 * PWEXPIRED so login knows they can still sort of
106acc2517fSmillert 		 * get in.
107acc2517fSmillert 		 */
108acc2517fSmillert 		if (expire < -dead) {
109acc2517fSmillert 			fprintf(back, BI_VALUE
110acc2517fSmillert 			    " errormsg Your password has expired\n");
111acc2517fSmillert 			fprintf(back, BI_REJECT "\n");
112acc2517fSmillert 			return (1);
113acc2517fSmillert 		}
114acc2517fSmillert 		if (expire < 0) {
115acc2517fSmillert 			if (lastchance) {
116ed05f6fdSmarkus 				struct passwd *npwd;
117ed05f6fdSmarkus 
118acc2517fSmillert 				endpwent();
119acc2517fSmillert 
120acc2517fSmillert 				/*
121acc2517fSmillert 				 * Only let them play this game once.
122acc2517fSmillert 				 * Set their password change time to 1.
123acc2517fSmillert 				 * This will most certainly cause any
124acc2517fSmillert 				 * expired password to be dead, as well.
125acc2517fSmillert 				 */
126ed05f6fdSmarkus 				npwd = pw_dup(pwd);
127ed05f6fdSmarkus 				npwd->pw_change = 1;
1289a60272cSmillert 				p = pwd_update(npwd, pwd);
1298fbd7fcbSdoug 				explicit_bzero(npwd->pw_passwd,
130ed05f6fdSmarkus 				    strlen(npwd->pw_passwd));
131ed05f6fdSmarkus 				free(npwd);
132acc2517fSmillert 				if (p != NULL) {
1331e50994aSmillert 					char *errval = auth_mkvalue(p);
1341e50994aSmillert 					if (errval != NULL) {
1351e50994aSmillert 						fprintf(back, BI_VALUE
1361e50994aSmillert 						    " errormsg %s", errval);
1371e50994aSmillert 						free(errval);
1381e50994aSmillert 					}
139acc2517fSmillert 					fprintf(back, BI_REJECT "\n");
140acc2517fSmillert 					return (1);
141acc2517fSmillert 				}
142acc2517fSmillert 			}
143acc2517fSmillert 			fprintf(back, BI_VALUE
144acc2517fSmillert 			    " errormsg Your password has expired\n");
145acc2517fSmillert 			fprintf(back, BI_PWEXPIRED "\n");
146acc2517fSmillert 			return (1);
147acc2517fSmillert 		}
148acc2517fSmillert 
149acc2517fSmillert 		/*
150acc2517fSmillert 		 * If their password is not expired but is about to expire
151acc2517fSmillert 		 * then warn them.
152acc2517fSmillert 		 */
153acc2517fSmillert 		if (expire <= warn) {
154acc2517fSmillert 			fprintf(back, BI_VALUE
155acc2517fSmillert 			    " warnmsg Your password expires on %s\n",
156acc2517fSmillert 			    ctime(&pwd->pw_change));
157acc2517fSmillert 		}
158acc2517fSmillert 	}
159acc2517fSmillert 	return (0);
160acc2517fSmillert }
161acc2517fSmillert 
162acc2517fSmillert static char *
pwd_update(const struct passwd * pwd,const struct passwd * opwd)1639a60272cSmillert pwd_update(const struct passwd *pwd, const struct passwd *opwd)
164acc2517fSmillert {
165acc2517fSmillert 	int tfd, pfd;
166acc2517fSmillert 
167acc2517fSmillert 	pw_init();
168acc2517fSmillert 	tfd = pw_lock(0);
169df69c215Sderaadt 	if (tfd == -1) {
170acc2517fSmillert 		if (errno == EEXIST)
171acc2517fSmillert 			return("the passwd file is busy.");
172acc2517fSmillert 		else
173acc2517fSmillert 			return("can't open passwd temp file");
174acc2517fSmillert 	}
175acc2517fSmillert 
176*b7041c07Sderaadt 	pfd = open(_PATH_MASTERPASSWD, O_RDONLY|O_CLOEXEC);
177df69c215Sderaadt 	if (pfd == -1) {
178acc2517fSmillert 		pw_abort();
179acc2517fSmillert 		return(strerror(errno));
180acc2517fSmillert 	}
181acc2517fSmillert 
1829a60272cSmillert 	pw_copy(pfd, tfd, pwd, opwd);
183df69c215Sderaadt 	if (pw_mkdb(pwd->pw_name, 0) == -1) {
184acc2517fSmillert 		pw_abort();
185acc2517fSmillert 		return("unable to update password database");
186acc2517fSmillert 	}
187acc2517fSmillert 
188acc2517fSmillert 	return(NULL);
189acc2517fSmillert }
190