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