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