]> granicus.if.org Git - linux-pam/blob - modules/pam_pwdb/pam_unix_pwupd.-c
Relevant BUGIDs: 133542
[linux-pam] / modules / pam_pwdb / pam_unix_pwupd.-c
1 /*
2  * $Id$
3  *
4  * This file contains the routines to update the passwd databases.
5  */
6
7 /* Implementation */
8
9 static int unix_update_db(pam_handle_t *pamh, int ctrl, const char *user,
10                           const char *pass_old, const char *pass_new)
11 {
12     const struct pwdb *pw=NULL;
13     const struct pwdb_entry *pwe=NULL;
14     pwdb_flag flag;
15     int retval, i;
16
17     D(("called."));
18
19     /* obtain default user record */
20
21     retval = pwdb_locate("user", PWDB_DEFAULT, user, PWDB_ID_UNKNOWN, &pw);
22     if (retval == PWDB_PASS_PHRASE_REQD) {
23         retval = pwdb_set_entry(pw, "pass_phrase"
24                                 , pass_old, 1+strlen(pass_old)
25                                 , NULL, NULL, 0);
26         if (retval == PWDB_SUCCESS)
27             retval = pwdb_locate("user", pw->source, user
28                                  , PWDB_ID_UNKNOWN, &pw);
29     }
30     pass_old = NULL;
31     
32     if ( retval != PWDB_SUCCESS ) {
33         _log_err(LOG_ALERT, "cannot identify user %s (uid=%d)"
34                  , user, getuid() );
35         pass_new = NULL;
36         if (pw)
37             (void) pwdb_delete(&pw);
38         return PAM_USER_UNKNOWN;
39     }
40
41     /* check that we can update all of the default databases */
42
43     retval = pwdb_flags("user", pw->source, &flag);
44
45     if ( retval != PWDB_SUCCESS || ( pwdb_on(flag,PWDB_F_NOUPDATE) ) ) {
46         _log_err(LOG_ERR, "cannot update default database for user %s"
47                  , user );
48         pass_new = NULL;
49         if (pw)
50             (void) pwdb_delete(&pw);
51         return PAM_PERM_DENIED;
52     }
53
54     /* If there was one, we delete the "last_change" entry */
55     retval = pwdb_get_entry(pw, "last_change", &pwe);
56     if (retval == PWDB_SUCCESS) {
57         (void) pwdb_entry_delete(&pwe);
58         pwdb_set_entry(pw, "last_change", NULL, -1, NULL, NULL, 0);
59     }
60
61     /*
62      * next check for pam.conf specified databases: shadow etc...  [In
63      * other words, pam.conf indicates which database the password is
64      * to be subsequently placed in: this is password migration].
65      */
66
67     if ( on(UNIX__SET_DB, ctrl) ) {
68         const char *db_token;
69         pwdb_type pt = _PWDB_MAX_TYPES;
70
71         if ( on(UNIX_UNIX, ctrl) ) {
72             db_token = "U";                        /* XXX - should be macro */
73             pt = PWDB_UNIX;
74         } else if ( on(UNIX_SHADOW, ctrl) ) {
75             db_token = "x";                        /* XXX - should be macro */
76             pt = PWDB_SHADOW;
77         } else if ( on(UNIX_RADIUS, ctrl) ) {
78             db_token = "R";                        /* XXX - is this ok? */
79             pt = PWDB_RADIUS;
80         } else {
81             _log_err(LOG_ALERT
82                      , "cannot determine database to use for authtok");
83             pass_new = NULL;
84             if (pw)
85                 (void) pwdb_delete(&pw);
86             return PAM_ABORT;                       /* we're in trouble */
87         }
88
89         /*
90          * Attempt to update the indicated database (only)
91          */
92
93         {
94             pwdb_type tpt[2];
95             tpt[0] = pt;
96             tpt[1] = _PWDB_MAX_TYPES;
97
98             /* Can we set entry in database? */
99             retval = pwdb_flags("user", tpt, &flag);
100             if (retval == PWDB_SUCCESS && !pwdb_on(flag,PWDB_F_NOUPDATE)) {
101                 /* YES. This database is available.. */
102
103                 /* Only update if it is not already in the default list */
104                 for (i=0; pw->source[i] != _PWDB_MAX_TYPES
105                          && pw->source[i] != pt ; ++i);
106                 if (pw->source[i] == _PWDB_MAX_TYPES) {
107                     const struct pwdb *tpw=NULL;
108
109                     /* copy database entry */
110                     if ((retval = pwdb_new(&tpw, 10)) != PWDB_SUCCESS
111                         || (retval = pwdb_merge(tpw, pw, PWDB_TRUE))
112                         != PWDB_SUCCESS) {
113                         _log_err(LOG_CRIT, "failed to obtain new pwdb: %s"
114                                  , pwdb_strerror(retval));
115                         retval = PAM_ABORT;
116                     } else
117                         retval = PAM_SUCCESS;
118                 
119                     /* set db_token */
120                     if (retval == PAM_SUCCESS) {
121                         retval = pwdb_set_entry(tpw, "defer_pass", db_token
122                                                 , 1+strlen(db_token)
123                                                 , NULL, NULL, 0);
124                         if (retval != PWDB_SUCCESS) {
125                             _log_err(LOG_ALERT, "set defer_pass -> %s"
126                                      , pwdb_strerror(retval));
127                             retval = PAM_PERM_DENIED;
128                         } else
129                             retval = PAM_SUCCESS;
130                     }
131
132                     /* update specific database */
133                     if (retval == PAM_SUCCESS) {
134                         retval = pwdb_replace("user", tpt
135                                               , user, PWDB_ID_UNKNOWN, &tpw);
136                         if (retval != PWDB_SUCCESS) {
137                             const char *service=NULL;
138                             (void) pam_get_item(pamh, PAM_SERVICE
139                                                 , (const void **)&service);
140                             _log_err(LOG_ALERT
141                                      , "(%s) specified database failed: %s"
142                                      , service
143                                      , pwdb_strerror(retval));
144                             retval = PAM_PERM_DENIED;
145                         } else {
146                             retval = PAM_SUCCESS;
147                         }
148                     }
149
150                     /* clean up temporary pwdb */
151                     if (tpw)
152                         (void) pwdb_delete(&tpw);
153                 }
154
155                 /* we can properly adopt new defer_pass */
156                 if (retval == PAM_SUCCESS) {
157                     /* failing here will mean we go back to former
158                        password location */
159                     (void) pwdb_set_entry(pw, "defer_pass", db_token
160                                           , 1+strlen(db_token), NULL, NULL, 0);
161                 }
162             }
163         }
164     }
165
166     /*
167      * the password will now be placed in appropriate (perhaps original) db
168      */
169
170     retval = pwdb_get_entry(pw, "uid", &pwe);
171     if (retval != PWDB_SUCCESS) {
172         _log_err(LOG_ALERT, "no uid!? (%s); %s", user, pwdb_strerror(retval));
173         pass_new = NULL;
174         if (pw)
175             (void) pwdb_delete(&pw);
176         return PAM_USER_UNKNOWN;
177     }
178
179     /* insert the passwd into the 'pw' structure */
180
181     retval = pwdb_set_entry(pw, "passwd", pass_new, 1+strlen(pass_new)
182                             , NULL, NULL, 0);
183     pass_new = NULL;
184     if (retval != PWDB_SUCCESS) {
185         _log_err(LOG_ALERT, "set2 failed; %s", pwdb_strerror(retval));
186         if (pw)
187             (void) pwdb_delete(&pw);
188         return PAM_AUTHTOK_LOCK_BUSY;
189     }
190
191     retval = pwdb_replace("user", pw->source, user
192                           , *((uid_t *)pwe->value), &pw);
193     if (retval != PWDB_SUCCESS) {
194         _log_err(LOG_ALERT, "user (%s/%d) update failed; %s"
195                  , user, *((uid_t *)pwe->value), pwdb_strerror(retval));
196         if (pw)
197             (void) pwdb_delete(&pw);
198         (void) pwdb_entry_delete(&pwe);
199         return PAM_ABORT;
200     }
201
202     if (retval != PWDB_SUCCESS) {
203
204         _log_err(LOG_ALERT, "user (%s/%d) update failed; %s"
205                  , user, *((uid_t *)pwe->value), pwdb_strerror(retval));
206         retval = PAM_ABORT;
207
208     } else {
209         /* password updated */
210
211         _log_err(LOG_INFO, "password for (%s/%d) changed by (%s/%d)"
212                  , user, *((uid_t *)pwe->value), getlogin(), getuid());
213         retval = PAM_SUCCESS;
214     }
215
216     /* tidy up */
217
218     (void) pwdb_entry_delete(&pwe);
219     if (pw)
220         (void) pwdb_delete(&pw);
221
222     return retval;
223 }
224
225 /* ******************************************************************
226  * Copyright (c) Andrew Morgan <morgan@parc.power.net> 1996,1997.
227  * Copyright (c) Cristian Gafton, <gafton@redhat.com> 1996, 1997.
228  *                                                All rights reserved
229  *
230  * Redistribution and use in source and binary forms, with or without
231  * modification, are permitted provided that the following conditions
232  * are met:
233  * 1. Redistributions of source code must retain the above copyright
234  *    notice, and the entire permission notice in its entirety,
235  *    including the disclaimer of warranties.
236  * 2. Redistributions in binary form must reproduce the above copyright
237  *    notice, this list of conditions and the following disclaimer in the
238  *    documentation and/or other materials provided with the distribution.
239  * 3. The name of the author may not be used to endorse or promote
240  *    products derived from this software without specific prior
241  *    written permission.
242  * 
243  * ALTERNATIVELY, this product may be distributed under the terms of
244  * the GNU Public License, in which case the provisions of the GPL are
245  * required INSTEAD OF the above restrictions.  (This clause is
246  * necessary due to a potential bad interaction between the GPL and
247  * the restrictions contained in a BSD-style copyright.)
248  * 
249  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
250  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
251  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
252  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
253  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
254  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
255  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
256  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
257  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
258  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
259  * OF THE POSSIBILITY OF SUCH DAMAGE.
260  */