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 |
*/
|