~ubuntu-branches/ubuntu/trusty/calife/trusty

1.2.2 by Christian Perrier
Import upstream version 3.0
1
/** Fichier auth.c
2
 **
3
 ** Routines de gestion des mots de passe
4
 **
1.2.3 by Christian Perrier
Import upstream version 3.0.1
5
 ** Copyright (c) 1991-2010 by Ollivier ROBERT
1.2.2 by Christian Perrier
Import upstream version 3.0
6
 ** A distribuer selon les regles de la GNU GPL General Public Licence
7
 ** Voir le fichier COPYING fourni.
8
 **
9
 **/
10
11
#ifndef lint
1.2.3 by Christian Perrier
Import upstream version 3.0.1
12
static const char * rcsid = "@(#) $Id: auth.c,v 0dcc27d2f900 2009/12/01 17:37:46 roberto $";
1.2.2 by Christian Perrier
Import upstream version 3.0
13
#endif
14
15
#include "config.h"     /* GNU configure */
16
17
                        /* fichier de configuration */
18
#include "conf.h"
19
20
static int  pam_pwcheck (struct passwd *calife, char * user_to_be, \
21
                         char * user_pass, int l_size);
22
static int  local_pwcheck (struct passwd *calife, char * user_to_be, \
23
                           char * user_pass, int l_size);
24
static void get_user_passwd(char * user_pass, int l_size);
25
26
/** authenticate_user
27
 **
28
 ** Demande et verifie le mot de passe pour l'utilisateur name
29
 ** Si name == root on ne fait rien.
30
 **
31
 ** Parametres :    name        char *  nom de l'utilisateur
32
 **                 user_to_be  char *  qui va-t-on devenir
33
 **                 this_time   char *  quand ?
34
 **                 tty         char *  sur quel tty
35
 **
36
 ** Retourne :      neant
37
 **
38
 ** Algo:
39
 **   si WITH_PAM est définit
40
 **     on essaie auth_pam()
41
 **     si ça plante, on continue avec un warning
42
 **     sinon retour ok
43
 **   fin
44
 **   vérification mdp
45
 ** 
46
 **/
47
48
void    
49
authenticate_user (char * who, char * user_to_be, char * when, char * tty)
50
{
51
    int             i = 0, rval, md5_here = 0;
52
    size_t          l_size = 0;
53
    
54
    struct  passwd  * calife;
55
56
    char    got_pass = AUTH_ERR;
57
    char    * pt_pass, * pt_enc, 
58
            * user_pass = NULL, * enc_pass = NULL, salt [10];
59
60
    /*
61
     * returns long usually
62
     */
63
#ifdef HAVE_WORKING_SYSCONF
64
    l_size = (size_t) sysconf (_SC_LINE_MAX);
65
#else
66
    l_size = MAX_STRING;
67
#endif /* HAVE_WORKING_SYSCONF */    
68
69
    user_pass = (char *) xalloc (l_size);
70
    enc_pass = (char *) xalloc (l_size);
71
72
     /*
73
      * become root again
74
      */
75
    GET_ROOT;
76
    calife = getpwnam (who);       /* null or locked password */
77
    RELEASE_ROOT;
78
79
    if (calife == NULL)
80
        die (1, "Bad pw data at line %d", __LINE__);
81
82
#ifdef WITH_PAM
83
    got_pass = pam_pwcheck (calife, user_to_be, user_pass, l_size);
84
#endif
85
86
    if (got_pass != AUTH_OK)
87
        got_pass = local_pwcheck (calife, user_to_be, user_pass, l_size);
88
89
    MESSAGE_1 ("Auth process returned %d\n", got_pass);
90
91
    if (got_pass == AUTH_NULL)
92
    {
93
        syslog (LOG_AUTH | LOG_ERR, "NULL CALIFE %s to %s on %s", who, \
94
                user_to_be, tty);
95
        closelog ();
96
        die (10, "Sorry.\n");
97
    }
98
99
    if (got_pass == AUTH_ERR)
100
    {
101
        syslog (LOG_AUTH | LOG_ERR, "BAD CALIFE %s to %s on %s", who, user_to_be, tty);
102
        closelog ();
103
        die (9, "Sorry.\n");
104
    }
105
106
    if (got_pass == AUTH_BADP)
107
    {
108
        syslog (LOG_AUTH|LOG_ERR, "GARBLED PASSWORD %s to unknown %s on%s",\
109
                who, user_to_be, tty);
110
        die (8, "Bad password string.\n");
111
    }
112
113
    free (user_pass);
114
    free (enc_pass);
115
}
116
117
/** local_pwcheck
118
 **
119
 ** Private method to check user password against local database
120
 **
121
 ** Parameters:   calife     struct passwd * requesting user
122
 **               user_to_be char *          target user
123
 **               user_pass  chat *          user password
124
 **               l_size     int             maximum size for password
125
 **
126
 ** Returns:      got_pass   Whether we got authenticated or not
127
 **/
128
129
static 
130
int local_pwcheck (struct passwd * calife, char * user_to_be, \
131
                   char * user_pass, int l_size)
132
{
133
    char * pt_pass, * who;
134
    int   i, rval, got_pass = AUTH_ERR, md5_here = 0;
135
136
#if defined (HAVE_SHADOW_H) && defined (HAVE_GETSPNAM) && !defined(UNUSED_SHADOW)
137
    struct  spwd  * scalife;
138
#endif
139
140
    MESSAGE_1 ("Testing w/o PAM with got_pass = %d\n", got_pass);
141
#if defined (HAVE_SHADOW_H) && defined (HAVE_GETSPNAM) && !defined(UNUSED_SHADOW)
142
1.2.3 by Christian Perrier
Import upstream version 3.0.1
143
    who = calife->pw_name;
1.2.2 by Christian Perrier
Import upstream version 3.0
144
    GET_ROOT;
145
    scalife = getspnam (who);       /* null or locked password */
146
    RELEASE_ROOT;
147
148
    /*
149
     * Goal is to manipulate only "calife", not both so if "scalife" is
150
     * valid, copy "scalife" interesting data into "calife"
151
     */
152
    if (scalife)
153
    {
154
        calife->pw_passwd =
155
            (char *) xalloc (strlen (scalife->sp_pwdp) + 1);
156
        strcpy (calife->pw_passwd, scalife->sp_pwdp);
157
    }
158
#endif /* HAVE_SHADOW_H */
159
160
    MESSAGE ("Not using PAM.\n");
161
    if ((*(calife->pw_passwd)) == '\0' || (*(calife->pw_passwd)) == '*')
162
        return (AUTH_NULL);
163
164
165
    if (getuid () != 0)
166
    {
167
        char    * pt_pass, * pt_enc, 
168
                * user_pass, * enc_pass, salt [10];
169
170
        user_pass = (char *) xalloc (l_size);
171
        enc_pass = (char *) xalloc (l_size);
172
173
        /*
174
         * cope with MD5 based crypt(3)
175
         */
176
        if (!strncmp (calife->pw_passwd, "$1$", 3)) /* MD5 */
177
        {
178
            char * pp = (char *) xalloc (strlen (calife->pw_passwd) + 1);
179
            char * md5_salt;
180
            char * md5_pass;
181
182
            strcpy (pp, calife->pw_passwd + 3);
183
            md5_salt = strtok (pp, "$");
184
            md5_pass = strtok (NULL, "$");
185
        
186
            if (md5_pass == NULL || 
187
                md5_salt == NULL ||
188
                (strlen (md5_salt) > 8))   /* garbled password */
189
  return (AUTH_BADP);
190
            MESSAGE_1 ("MD5 password found, salt=%s\n", md5_salt);
191
            strcpy (salt, md5_salt);            
192
            free (pp);
193
        }
194
        else
195
        {
196
            strncpy (salt, calife->pw_passwd, 2);
197
            salt [2] = '\0';
198
        }
199
200
        for ( i = 0; i < MAX_ATTEMPTS; i ++ )
201
        {
202
            get_user_passwd (user_pass, l_size);
203
            /*
204
             * At this point, either we have a password or
205
             * it has died already
206
             */
207
            pt_enc = (char *) crypt (user_pass, calife->pw_passwd);
208
            /*
209
             * Wipe out the cleartext password
210
             */
211
            memset (user_pass, '\0', l_size);
212
213
            /*
214
             * Move from the static buffer intoa safe location of our own
215
             */
216
            memset (enc_pass, '\0', l_size);
217
            strcpy (enc_pass, pt_enc);
218
            /*
219
             * assumes standard crypt(3)
220
             */
221
            if (!strcmp (enc_pass, calife->pw_passwd))
222
            {
223
                got_pass = AUTH_OK;
224
                break;
225
            }
226
        } /* for */
227
    } /* end if for getuid() */
228
    return (got_pass);
229
}
230
231
/** pam_pwcheck
232
 **
233
 ** Private method to check user password against PAM backend.
234
 **
235
 ** Parameters:   calife     struct passwd * target user
236
 **               user_to_be char *          target user
237
 **               user_pass  chat *          user password
238
 **               l_size     int             maximum size for password
239
 **
240
 ** Returns:      whether the password was obtained through PAM or not 
241
 **               (including failure in PAM process)
242
 **/
243
244
static 
245
int pam_pwcheck (struct passwd *calife, char * user_to_be, char * user_pass,\
246
                 int l_size)
247
{
248
    char * pt_pass, * who;
249
    int   i, rval, got_pass = AUTH_ERR;
250
251
#ifdef WITH_PAM
252
    who = calife->pw_name;
253
    if (getuid () != 0)
254
    {
255
        MESSAGE ("Trying PAM\n");
256
        for ( i = 0; i < MAX_ATTEMPTS; i++ )
257
        {
258
            get_user_passwd (user_pass, l_size);
259
            /*
260
261
             * At this point, either we have a password or
262
             * it has died already
263
             */
264
            MESSAGE ("Testing auth with PAM.\n");
265
266
            rval = auth_pam (&calife, user_pass);
267
268
            MESSAGE_1 ("PAM auth_pam returned %d\n", rval);
269
            if (rval)
270
            {
271
                syslog (LOG_AUTH | LOG_ERR, "PAM failed with code %d for %s", rval, who);
272
                /*
273
                 * Check return value:
274
                 * - 0:   auth succeeded
275
                 * - >0:  auth failed.
276
                 */ 
277
                /* Fallback to previous methods? */
278
            }
279
            else
280
            {
281
                syslog (LOG_AUTH | LOG_INFO, "PAM auth succeeded for %s", who);
282
                got_pass = AUTH_OK;
283
                break;
284
            }
285
        } /* end for */
286
    }
287
    else
288
        got_pass = AUTH_OK;
289
#endif
290
    return got_pass;
291
}
292
293
/** get_user_passwd
294
 **
295
 ** When not using PAM, get the user's password with getpass/getpassphrase
296
 **
297
 ** Parameters:    user_pass    char * password
298
 **                l_size       int    maximum size
299
 **
300
 ** Returns:       nothing
301
 **/
302
303
static
304
void get_user_passwd(char * user_pass, int l_size)
305
{
306
    char * pt_pass;
307
308
    /* XXX Solaris 10
309
     * Solaris 5.10 (and maybe before) truncate getpass() entry
310
     * to 8 bytes, use getpassphrase(3) instead
311
     *
312
     * Use getpassphrase(3) if available
313
     */
314
#ifdef HAVE_GETPASSPHRASE
315
        pt_pass = (char *) getpassphrase ("Password:");
316
#else
317
        pt_pass = (char *) getpass ("Password:");
318
#endif /* HAVE_GETPASSPHRASE */
319
    /* 
320
     * XXX don't assume getpass(3) will check the buffer
321
     * length. Linux glibc apparently lacks such checking and
322
     * will happily segfault if the previous entered password
323
     * was too big.
324
     * cf. <URL:http://www.securityfocus.com/archive/1/355510>
325
     */
326
    if (pt_pass == NULL)
327
        die(1, "Corrupted or too long password");
328
    memset (user_pass, '\0', l_size);
329
    /*
330
     * Be a bit more careful there
331
     */
332
    strncpy (user_pass, pt_pass, l_size);
333
    user_pass[l_size - 1] = '\0';
334
}
335
336
/*
337
338
  get_user_data
339
    calife
340
    scalife
341
  get_user_password
342
    (select getpass or getpassphrase)
343
  check_passwd
344
    if_pam
345
      auth_pam
346
    else
347
      (select encryption method based on sig $nn$salt$passwd)
348
    end
349
 */