1 /*
2 * This program is designed to run with sufficient privilege
3 * to read and write all of the unix password databases.
4 * Its purpose is to allow updating the databases when
5 * SELinux confinement of the caller domain prevents them to
6 * do that themselves.
7 *
8 * The password is read from the standard input. The exit status of
9 * this program indicates whether the password was updated or not.
10 *
11 * Copyright information is located at the end of the file.
12 *
13 */
14
15 #include "config.h"
16
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <syslog.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <pwd.h>
26 #include <shadow.h>
27 #include <signal.h>
28 #include <time.h>
29 #include <sys/time.h>
30
31 #include <security/_pam_types.h>
32 #include <security/_pam_macros.h>
33
34 #include "passverify.h"
35 #include "pam_inline.h"
36
37 static int
38 set_password(const char *forwho, const char *shadow, const char *remember)
39 {
40 struct passwd *pwd = NULL;
41 int retval;
42 char pass[PAM_MAX_RESP_SIZE + 1];
43 char towhat[PAM_MAX_RESP_SIZE + 1];
44 int npass = 0;
45 /* we don't care about number format errors because the helper
46 should be called internally only */
47 int doshadow = atoi(shadow);
48 int nremember = atoi(remember);
49 char *passwords[] = { pass, towhat };
50
51 /* read the password from stdin (a pipe from the pam_unix module) */
52
53 npass = pam_read_passwords(STDIN_FILENO, 2, passwords);
54
55 if (npass != 2) { /* is it a valid password? */
56 if (npass == 1) {
57 helper_log_err(LOG_DEBUG, "no new password supplied");
58 pam_overwrite_array(pass);
59 } else {
60 helper_log_err(LOG_DEBUG, "no valid passwords supplied");
61 }
62 return PAM_AUTHTOK_ERR;
63 }
64
65 if (lock_pwdf() != PAM_SUCCESS) {
66 pam_overwrite_array(pass);
67 pam_overwrite_array(towhat);
68 return PAM_AUTHTOK_LOCK_BUSY;
69 }
70
71 pwd = getpwnam(forwho);
72
73 if (pwd == NULL) {
74 retval = PAM_USER_UNKNOWN;
75 goto done;
76 }
77
78 /* If real caller uid is not root we must verify that
79 received old pass agrees with the current one.
80 We always allow change from null pass. */
81 if (getuid()) {
82 retval = helper_verify_password(forwho, pass, 1);
83 if (retval != PAM_SUCCESS) {
84 goto done;
85 }
86 }
87
88 /* first, save old password */
89 if (save_old_password(forwho, pass, nremember)) {
90 retval = PAM_AUTHTOK_ERR;
91 goto done;
92 }
93
94 if (doshadow || is_pwd_shadowed(pwd)) {
95 retval = unix_update_shadow(forwho, towhat);
96 if (retval == PAM_SUCCESS)
97 if (!is_pwd_shadowed(pwd))
98 retval = unix_update_passwd(forwho, "x");
99 } else {
100 retval = unix_update_passwd(forwho, towhat);
101 }
102
103 done:
104 pam_overwrite_array(pass);
105 pam_overwrite_array(towhat);
106
107 unlock_pwdf();
108
109 if (retval == PAM_SUCCESS) {
110 return PAM_SUCCESS;
111 } else {
112 return PAM_AUTHTOK_ERR;
113 }
114 }
115
116 int main(int argc, char *argv[])
117 {
118 char *option;
119
120 /*
121 * Catch or ignore as many signal as possible.
122 */
123 setup_signals();
124
125 /*
126 * we establish that this program is running with non-tty stdin.
127 * this is to discourage casual use. It does *NOT* prevent an
128 * intruder from repeatadly running this program to determine the
129 * password of the current user (brute force attack, but one for
130 * which the attacker must already have gained access to the user's
131 * account).
132 */
133
134 if (isatty(STDIN_FILENO) || argc != 5 ) {
135 helper_log_err(LOG_NOTICE
136 ,"inappropriate use of Unix helper binary [UID=%d]"
137 ,getuid());
138 fprintf(stderr
139 ,"This binary is not designed for running in this way\n"
140 "-- the system administrator has been informed\n");
141 sleep(10); /* this should discourage/annoy the user */
142 return PAM_SYSTEM_ERR;
143 }
144
145 /* We must be root to read/update shadow.
146 */
147 if (geteuid() != 0) {
148 return PAM_CRED_INSUFFICIENT;
149 }
150
151 option = argv[2];
152
153 if (strcmp(option, "update") == 0) {
154 /* Attempting to change the password */
155 return set_password(argv[1], argv[3], argv[4]);
156 }
157
158 return PAM_SYSTEM_ERR;
159 }
160
161 /*
162 * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
163 * Copyright (c) Red Hat, Inc., 2007, 2008. All rights reserved
164 *
165 * Redistribution and use in source and binary forms, with or without
166 * modification, are permitted provided that the following conditions
167 * are met:
168 * 1. Redistributions of source code must retain the above copyright
169 * notice, and the entire permission notice in its entirety,
170 * including the disclaimer of warranties.
171 * 2. Redistributions in binary form must reproduce the above copyright
172 * notice, this list of conditions and the following disclaimer in the
173 * documentation and/or other materials provided with the distribution.
174 * 3. The name of the author may not be used to endorse or promote
175 * products derived from this software without specific prior
176 * written permission.
177 *
178 * ALTERNATIVELY, this product may be distributed under the terms of
179 * the GNU Public License, in which case the provisions of the GPL are
180 * required INSTEAD OF the above restrictions. (This clause is
181 * necessary due to a potential bad interaction between the GPL and
182 * the restrictions contained in a BSD-style copyright.)
183 *
184 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
185 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
186 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
187 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
188 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
189 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
190 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
191 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
192 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
193 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
194 * OF THE POSSIBILITY OF SUCH DAMAGE.
195 */