]> granicus.if.org Git - shadow/blob - libmisc/age.c
* NEWS, libmisc/chowntty.c: Fix a race condition that could lead to
[shadow] / libmisc / age.c
1 /*
2  * Copyright (c) 1989 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 1998, Marek Michałkiewicz
4  * Copyright (c) 2001 - 2006, Tomasz Kłoczko
5  * Copyright (c) 2008       , Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <config.h>
34
35 #include <sys/types.h>
36 #include <stdio.h>
37 #include <time.h>
38 #include <errno.h>
39 #include "prototypes.h"
40 #include "defines.h"
41 #include "exitcodes.h"
42 #include <pwd.h>
43 #include <grp.h>
44
45 #ident "$Id$"
46
47 #ifndef PASSWD_PROGRAM
48 #define PASSWD_PROGRAM "/bin/passwd"
49 #endif
50 /*
51  * expire - force password change if password expired
52  *
53  *      expire() calls /bin/passwd to change the user's password
54  *      if it has expired.
55  */
56 int expire (const struct passwd *pw, const struct spwd *sp)
57 {
58         int status;
59         pid_t child;
60         pid_t pid;
61
62         if (NULL == sp) {
63                 sp = pwd_to_spwd (pw);
64         }
65
66         /*
67          * See if the user's password has expired, and if so
68          * force them to change their password.
69          */
70
71         status = isexpired (pw, sp);
72         switch (status) {
73         case 0:
74                 return 0;
75         case 1:
76                 (void) fputs (_("Your password has expired."), stdout);
77                 break;
78         case 2:
79                 (void) fputs (_("Your password is inactive."), stdout);
80                 break;
81         case 3:
82                 (void) fputs (_("Your login has expired."), stdout);
83                 break;
84         }
85
86         /*
87          * Setting the maximum valid period to less than the minimum
88          * valid period means that the minimum period will never
89          * occur while the password is valid, so the user can never
90          * change that password.
91          */
92
93         if ((status > 1) || (sp->sp_max < sp->sp_min)) {
94                 (void) puts (_("  Contact the system administrator."));
95                 exit (1);
96         }
97         (void) puts (_("  Choose a new password."));
98         (void) fflush (stdout);
99
100         /*
101          * Close all the files so that unauthorized access won't
102          * occur.  This needs to be done anyway because those files
103          * might become stale after "passwd" is executed.
104          */
105
106         endspent ();
107         endpwent ();
108 #ifdef SHADOWGRP
109         endsgent ();
110 #endif
111         endgrent ();
112
113         /*
114          * Execute the /bin/passwd command.  The exit status will be
115          * examined to see what the result is.  If there are any
116          * errors the routine will exit.  This forces the user to
117          * change their password before being able to use the account.
118          */
119
120         pid = fork ();
121         if (0 == pid) {
122                 int err;
123
124                 /*
125                  * Set the UID to be that of the user.  This causes
126                  * passwd to work just like it would had they executed
127                  * it from the command line while logged in.
128                  */
129                 if (setup_uid_gid (pw, 0) != 0) {
130                         _exit (126);
131                 }
132
133                 execl (PASSWD_PROGRAM, PASSWD_PROGRAM, pw->pw_name, (char *) 0);
134                 err = errno;
135                 perror ("Can't execute " PASSWD_PROGRAM);
136                 _exit ((ENOENT == err) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
137         } else if ((pid_t) -1 == pid) {
138                 perror ("fork");
139                 exit (1);
140         }
141
142         while (((child = wait (&status)) != pid) && (child != (pid_t)-1));
143
144         if ((child == pid) && (0 == status)) {
145                 return 1;
146         }
147
148         exit (1);
149  /*NOTREACHED*/}
150
151 /*
152  * agecheck - see if warning is needed for password expiration
153  *
154  *      agecheck sees how many days until the user's password is going
155  *      to expire and warns the user of the pending password expiration.
156  */
157
158 void agecheck (const struct passwd *pw, const struct spwd *sp)
159 {
160         long now = (long) time ((time_t *) 0) / SCALE;
161         long remain;
162
163         if (NULL == sp) {
164                 sp = pwd_to_spwd (pw);
165         }
166
167         /*
168          * The last, max, and warn fields must be supported or the
169          * warning period cannot be calculated.
170          */
171
172         if (   (-1 == sp->sp_lstchg)
173             || (-1 == sp->sp_max)
174             || (-1 == sp->sp_warn)) {
175                 return;
176         }
177         remain = sp->sp_lstchg + sp->sp_max - now;
178         if (remain <= sp->sp_warn) {
179                 remain /= DAY / SCALE;
180                 if (remain > 1) {
181                         (void) printf (_("Your password will expire in %ld days.\n"),
182                                        remain);
183                 } else if (1 == remain) {
184                         (void) puts (_("Your password will expire tomorrow."));
185                 } else if (remain == 0) {
186                         (void) puts (_("Your password will expire today."));
187                 }
188         }
189 }
190