~xnox/ubuntu/quantal/shadow/clear-locks

« back to all changes in this revision

Viewing changes to libmisc/obscure.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2009-05-05 09:45:21 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20090505094521-wpk2wn3q7957tlah
Tags: 1:4.1.3.1-1ubuntu1
* Merge from debian unstable, remaining changes:
  - Ubuntu specific:
    + debian/login.defs: use SHA512 by default for password crypt routine.
  - debian/patches/stdout-encrypted-password.patch: chpasswd can report
    password hashes on stdout (debian bug 505640).
  - debian/login.pam: Enable SELinux support (debian bug 527106).
  - debian/securetty.linux: support Freescale MX-series (debian bug 527095).
* Add debian/patches/300_lastlog_failure: fixed upstream (debian bug 524873).
* Drop debian/patches/593_omit_lastchange_field_if_clock_is_misset: fixed
  upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright 1989 - 1994, Julianne Frances Haugh
 
2
 * Copyright (c) 1989 - 1994, Julianne Frances Haugh
 
3
 * Copyright (c) 1996 - 1999, Marek Michałkiewicz
 
4
 * Copyright (c) 2003 - 2005, Tomasz Kłoczko
 
5
 * Copyright (c) 2007 - 2008, Nicolas François
3
6
 * All rights reserved.
4
7
 *
5
8
 * Redistribution and use in source and binary forms, with or without
10
13
 * 2. Redistributions in binary form must reproduce the above copyright
11
14
 *    notice, this list of conditions and the following disclaimer in the
12
15
 *    documentation and/or other materials provided with the distribution.
13
 
 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14
 
 *    may be used to endorse or promote products derived from this software
15
 
 *    without specific prior written permission.
 
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.
16
19
 *
17
 
 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18
 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 
 * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21
 
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 
 * SUCH DAMAGE.
 
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.
28
31
 */
29
32
 
30
33
#include <config.h>
31
34
 
32
35
#ifndef USE_PAM
33
36
 
34
 
#ident "$Id: obscure.c 1668 2008-01-06 13:20:25Z nekral-guest $"
 
37
#ident "$Id: obscure.c 2352 2008-09-06 15:59:28Z nekral-guest $"
35
38
 
36
39
 
37
40
/*
47
50
/*
48
51
 * can't be a palindrome - like `R A D A R' or `M A D A M'
49
52
 */
50
 
static int palindrome (unused const char *old, const char *new)
 
53
static bool palindrome (unused const char *old, const char *new)
51
54
{
52
55
        int i, j;
53
56
 
54
57
        i = strlen (new);
55
58
 
56
 
        for (j = 0; j < i; j++)
57
 
                if (new[i - j - 1] != new[j])
58
 
                        return 0;
 
59
        for (j = 0; j < i; j++) {
 
60
                if (new[i - j - 1] != new[j]) {
 
61
                        return false;
 
62
                }
 
63
        }
59
64
 
60
 
        return 1;
 
65
        return true;
61
66
}
62
67
 
63
68
/*
64
69
 * more than half of the characters are different ones.
65
70
 */
66
71
 
67
 
static int similar (const char *old, const char *new)
 
72
static bool similar (const char *old, const char *new)
68
73
{
69
74
        int i, j;
70
75
 
74
79
         * the new password is long enough.  Please feel free to suggest
75
80
         * something better...  --marekm
76
81
         */
77
 
        if (strlen (new) >= 8)
78
 
                return 0;
 
82
        if (strlen (new) >= 8) {
 
83
                return false;
 
84
        }
79
85
 
80
 
        for (i = j = 0; new[i] && old[i]; i++)
81
 
                if (strchr (new, old[i]))
 
86
        for (i = j = 0; ('\0' != new[i]) && ('\0' != old[i]); i++) {
 
87
                if (strchr (new, old[i]) != NULL) {
82
88
                        j++;
83
 
 
84
 
        if (i >= j * 2)
85
 
                return 0;
86
 
 
87
 
        return 1;
 
89
                }
 
90
        }
 
91
 
 
92
        if (i >= j * 2) {
 
93
                return false;
 
94
        }
 
95
 
 
96
        return true;
88
97
}
89
98
 
90
99
/*
93
102
 
94
103
static int simple (unused const char *old, const char *new)
95
104
{
96
 
        int digits = 0;
97
 
        int uppers = 0;
98
 
        int lowers = 0;
99
 
        int others = 0;
 
105
        bool digits = false;
 
106
        bool uppers = false;
 
107
        bool lowers = false;
 
108
        bool others = false;
100
109
        int size;
101
110
        int i;
102
111
 
103
 
        for (i = 0; new[i]; i++) {
104
 
                if (isdigit (new[i]))
105
 
                        digits++;
106
 
                else if (isupper (new[i]))
107
 
                        uppers++;
108
 
                else if (islower (new[i]))
109
 
                        lowers++;
110
 
                else
111
 
                        others++;
 
112
        for (i = 0; '\0' != new[i]; i++) {
 
113
                if (isdigit (new[i])) {
 
114
                        digits = true;
 
115
                } else if (isupper (new[i])) {
 
116
                        uppers = true;
 
117
                } else if (islower (new[i])) {
 
118
                        lowers = true;
 
119
                } else {
 
120
                        others = true;
 
121
                }
112
122
        }
113
123
 
114
124
        /*
117
127
         */
118
128
 
119
129
        size = 9;
120
 
        if (digits)
121
 
                size--;
122
 
        if (uppers)
123
 
                size--;
124
 
        if (lowers)
125
 
                size--;
126
 
        if (others)
127
 
                size--;
128
 
 
129
 
        if (size <= i)
130
 
                return 0;
131
 
 
132
 
        return 1;
 
130
        if (digits) {
 
131
                size--;
 
132
        }
 
133
        if (uppers) {
 
134
                size--;
 
135
        }
 
136
        if (lowers) {
 
137
                size--;
 
138
        }
 
139
        if (others) {
 
140
                size--;
 
141
        }
 
142
 
 
143
        if (size <= i) {
 
144
                return false;
 
145
        }
 
146
 
 
147
        return true;
133
148
}
134
149
 
135
150
static char *str_lower (char *string)
136
151
{
137
152
        char *cp;
138
153
 
139
 
        for (cp = string; *cp; cp++)
 
154
        for (cp = string; '\0' != *cp; cp++) {
140
155
                *cp = tolower (*cp);
 
156
        }
141
157
        return string;
142
158
}
143
159
 
157
173
#endif
158
174
#endif
159
175
 
160
 
        if (strcmp (new, old) == 0)
 
176
        if (strcmp (new, old) == 0) {
161
177
                return _("no change");
 
178
        }
162
179
 
163
180
        newmono = str_lower (xstrdup (new));
164
181
        oldmono = str_lower (xstrdup (old));
166
183
        strcpy (wrapped, oldmono);
167
184
        strcat (wrapped, oldmono);
168
185
 
169
 
        if (palindrome (oldmono, newmono))
 
186
        if (palindrome (oldmono, newmono)) {
170
187
                msg = _("a palindrome");
171
 
 
172
 
        if (!msg && strcmp (oldmono, newmono) == 0)
 
188
        } else if (strcmp (oldmono, newmono) == 0) {
173
189
                msg = _("case changes only");
174
 
 
175
 
        if (!msg && similar (oldmono, newmono))
 
190
        } else if (similar (oldmono, newmono)) {
176
191
                msg = _("too similar");
177
 
 
178
 
        if (!msg && simple (old, new))
 
192
        } else if (simple (old, new)) {
179
193
                msg = _("too simple");
180
 
 
181
 
        if (!msg && strstr (wrapped, newmono))
 
194
        } else if (strstr (wrapped, newmono) != NULL) {
182
195
                msg = _("rotated");
183
 
 
 
196
        } else {
184
197
#ifdef HAVE_LIBCRACK
185
 
        /*
186
 
         * Invoke Alec Muffett's cracklib routines.
187
 
         */
 
198
                /*
 
199
                 * Invoke Alec Muffett's cracklib routines.
 
200
                 */
188
201
 
189
 
        if (!msg && (dictpath = getdef_str ("CRACKLIB_DICTPATH")))
 
202
                dictpath = getdef_str ("CRACKLIB_DICTPATH");
 
203
                if (NULL != dictpath) {
190
204
#ifdef HAVE_LIBCRACK_PW
191
 
                msg = FascistCheckPw (new, dictpath, pwdp);
 
205
                        msg = FascistCheckPw (new, dictpath, pwdp);
192
206
#else
193
 
                msg = FascistCheck (new, dictpath);
194
 
#endif
195
 
#endif
 
207
                        msg = FascistCheck (new, dictpath);
 
208
#endif
 
209
                }
 
210
#endif
 
211
        }
196
212
        strzero (newmono);
197
213
        strzero (oldmono);
198
214
        strzero (wrapped);
203
219
        return msg;
204
220
}
205
221
 
206
 
 /*ARGSUSED*/
207
 
    static const char *obscure_msg (const char *old, const char *new,
 
222
/*ARGSUSED*/
 
223
static const char *obscure_msg (const char *old, const char *new,
208
224
                                    const struct passwd *pwdp)
209
225
{
210
226
        int maxlen, oldlen, newlen;
215
231
        oldlen = strlen (old);
216
232
        newlen = strlen (new);
217
233
 
218
 
        if (newlen < getdef_num ("PASS_MIN_LEN", 0))
 
234
        if (newlen < getdef_num ("PASS_MIN_LEN", 0)) {
219
235
                return _("too short");
 
236
        }
220
237
 
221
238
        /*
222
239
         * Remaining checks are optional.
223
240
         */
224
 
        if (!getdef_bool ("OBSCURE_CHECKS_ENAB"))
 
241
        if (!getdef_bool ("OBSCURE_CHECKS_ENAB")) {
225
242
                return NULL;
 
243
        }
226
244
 
227
245
        msg = password_check (old, new, pwdp);
228
 
        if (msg)
 
246
        if (NULL != msg) {
229
247
                return msg;
 
248
        }
230
249
 
231
 
        if ((result = getdef_str ("ENCRYPT_METHOD")) == NULL) {
 
250
        result = getdef_str ("ENCRYPT_METHOD");
 
251
        if (NULL == result) {
232
252
        /* The traditional crypt() truncates passwords to 8 chars.  It is
233
253
           possible to circumvent the above checks by choosing an easy
234
254
           8-char password and adding some random characters to it...
235
255
           Example: "password$%^&*123".  So check it again, this time
236
256
           truncated to the maximum length.  Idea from npasswd.  --marekm */
237
257
 
238
 
                if (getdef_bool ("MD5_CRYPT_ENAB"))
 
258
                if (getdef_bool ("MD5_CRYPT_ENAB")) {
239
259
                        return NULL;
 
260
                }
240
261
 
241
262
        } else {
242
263
 
243
 
                if (   !strcmp (result, "MD5")
 
264
                if (   (strcmp (result, "MD5")    == 0)
244
265
#ifdef USE_SHA_CRYPT
245
 
                    || !strcmp (result, "SHA256")
246
 
                    || !strcmp (result, "SHA512")
 
266
                    || (strcmp (result, "SHA256") == 0)
 
267
                    || (strcmp (result, "SHA512") == 0)
247
268
#endif
248
 
                    )
 
269
                    ) {
249
270
                        return NULL;
 
271
                }
250
272
 
251
273
        }
252
274
        maxlen = getdef_num ("PASS_MAX_LEN", 8);
253
 
        if (oldlen <= maxlen && newlen <= maxlen)
 
275
        if (   (oldlen <= maxlen)
 
276
            && (newlen <= maxlen)) {
254
277
                return NULL;
 
278
        }
255
279
 
256
280
        new1 = xstrdup (new);
257
281
        old1 = xstrdup (old);
258
 
        if (newlen > maxlen)
 
282
        if (newlen > maxlen) {
259
283
                new1[maxlen] = '\0';
260
 
        if (oldlen > maxlen)
 
284
        }
 
285
        if (oldlen > maxlen) {
261
286
                old1[maxlen] = '\0';
 
287
        }
262
288
 
263
289
        msg = password_check (old1, new1, pwdp);
264
290
 
282
308
{
283
309
        const char *msg = obscure_msg (old, new, pwdp);
284
310
 
285
 
        if (msg) {
 
311
        if (NULL != msg) {
286
312
                printf (_("Bad password: %s.  "), msg);
287
313
                return 0;
288
314
        }