2 * Copyright 1992 - 1994, Julianne Frances Haugh
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * 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.
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
33 RCSID("$Id: pwauth.c,v 1.11 2000/08/26 18:27:17 marekm Exp $")
35 #include <sys/types.h>
40 #include "prototypes.h"
53 #ifdef __linux__ /* standard password prompt by default */
54 static const char *PROMPT = gettext_noop("Password: ");
56 static const char *PROMPT = gettext_noop("%s's Password: ");
59 extern char *getpass();
60 extern char *getpass_with_echo();
64 * Look-up table for bound-in methods. Put the name that the
65 * method is known by in the password field as "name" and a
66 * pointer to the function
71 int (*func)(const char *, int, const char *);
77 static struct method methods[] = {
83 #endif /* AUTH_METHODS */
85 int wipe_clear_pass = 1;
86 char *clear_pass = NULL;
89 * _old_auth - perform getpass/crypt authentication
91 * _old_auth gets the user's cleartext password and encrypts it
92 * using the salt in the encrypted password. The results are
97 _old_auth(const char *cipher, const char *user, int reason, const char *input)
105 char challenge_info[40];
111 char o_challenge_info[OPIE_CHALLENGE_MAX + 1];
114 * This implementation is based almost entirely on the SKEY code
115 * above. Thus the opie struct is called skey, etc. I am unaware
116 * if the system works at the same time, but I cannot imagine why
117 * anyone would want to do this....
120 * Made the OPIE code separate from the S/Key code. Now
121 * (conceivably) both can be compiled in and function apart from
122 * one another (assuming a sysadmin really wants to maintain OPIE
123 * and an S/Key databases....).
125 * Also cleaned up the code a bit. Will be adding second-prompt
126 * support (the traditional Echo-on S/Key/OPIE-only prompts to let
127 * the users see the one-time passwords they are typing/pasting
134 * There are programs for adding and deleting authentication data.
137 if (reason == PW_ADD || reason == PW_DELETE)
141 * There are even programs for changing the user name ...
144 if (reason == PW_CHANGE && input != (char *) 0)
150 * When we change a password and we are root, we don't prompt.
151 * This is so root can change any password without having to
152 * know it. This is a policy decision that might have to be
156 if (reason == PW_CHANGE && getuid () == 0)
162 * When we are logging in a user with no ciphertext password,
163 * we don't prompt for the password or anything. In reality
164 * the user could just hit <ENTER>, so it doesn't really
168 if (cipher == (char *) 0 || *cipher == '\0')
173 * If the user has an S/KEY entry show them the pertinent info
174 * and then we can try validating the created cyphertext and the SKEY.
175 * If there is no SKEY information we default to not using SKEY.
178 if (skeychallenge (&skey, user, challenge_info) == 0)
184 * Ditto above, for OPIE passwords.
188 o_challenge_info[0] = '\0';
189 if (opiechallenge(&opie, user, o_challenge_info) == 0)
193 opieverify(&opie, (char *)NULL);
195 * This call to opieverify is necessary within OPIE's interface:
196 * Every call to opiechallenge(), which checks to see if the user
197 * has an OPIE password, and if so get the challenge, must be
198 * accompanied by exactly one call to opieverify, which clears
199 * any outstanding locks, and otherwise cleans up.
205 * Prompt for the password as required. FTPD and REXECD both
206 * get the cleartext password for us.
209 if (reason != PW_FTP && reason != PW_REXEC && !input) {
210 if (! (cp = getdef_str ("LOGIN_STRING")))
214 printf ("[%s]\n", challenge_info);
219 printf("[ %s ]\n", o_challenge_info);
222 snprintf(prompt, sizeof prompt, cp, user);
223 clear = getpass(prompt);
233 * Convert the cleartext password into a ciphertext string.
234 * If the two match, the return value will be zero, which is
235 * SUCCESS. Otherwise we see if SKEY is being used and check
236 * the results there as well.
239 retval = strcmp(pw_encrypt(input, cipher), cipher);
243 * This is required because using OPIE, opieverify() MUST be called
244 * opiechallenge() above even if OPIE isn't being used in this case,
245 * so locks get released, etc.
249 if ((retval == 0) && use_opie)
250 opieverify(&opie, (char *)NULL);
253 #if (defined(SKEY) || defined(OPIE))
255 * If (1) The password fails to match, and
256 * (2) The password is empty and
257 * (3) We are using OPIE or S/Key, then
258 * ...Re-prompt, with echo on.
261 if (retval && !input[0] &&
270 strncat(prompt, _("(Echo on) "),
271 (sizeof(prompt) - strlen(prompt)));
272 clear = getpass_with_echo(prompt);
283 if (retval && use_skey) {
286 #if 0 /* some skey libs don't have skey_passcheck. --marekm */
287 passcheck = skey_passcheck(user, input);
289 if (skeyverify(&skey, input) == 0)
298 if (retval && use_opie) {
299 if (opieverify(&opie, input) == 0)
305 * Things like RADIUS authentication may need the password -
306 * if the external variable wipe_clear_pass is zero, we will
307 * not wipe it (the caller should wipe clear_pass when it is
308 * no longer needed). --marekm
312 if (wipe_clear_pass && clear && *clear)
319 * _pw_auth - perform alternate password authentication
321 * pw_auth executes the alternate password authentication method
322 * described in the user's password entry. _pw_auth does the real
323 * work, pw_auth splits the authentication string into individual
328 _pw_auth(const char *command, const char *user, int reason, const char *input)
330 RETSIGTYPE (*sigint)();
331 RETSIGTYPE (*sigquit)();
333 RETSIGTYPE (*sigtstp)();
338 char * const argv[5];
341 char *empty_env = NULL;
345 * Start with a quick sanity check. ALL command names must
346 * be fully-qualified path names.
349 if (command[0] != '/')
353 * Set the keyboard signals to be ignored. When the user kills
354 * the child we don't want the parent dying as well.
357 sigint = signal (SIGINT, SIG_IGN);
358 sigquit = signal (SIGQUIT, SIG_IGN);
360 sigtstp = signal (SIGTSTP, SIG_IGN);
364 * FTP and REXEC reasons don't give the program direct access
365 * to the user. This means that the program can only get input
366 * from this function. So we set up a pipe for that purpose.
369 use_pipe = (reason == PW_FTP || reason == PW_REXEC);
375 * The program will be forked off with the parent process waiting
376 * on the child to tell it how successful it was.
379 switch (pid = fork ()) {
382 * The fork() failed completely. Clean up as needed and
383 * return to the caller.
394 * Let the child catch the SIGINT and SIGQUIT
395 * signals. The parent, however, will continue
398 signal (SIGINT, SIG_DFL);
399 signal (SIGQUIT, SIG_DFL);
402 * Set up the command line. The first argument is
403 * the name of the command being executed. The
404 * second is the command line option for the reason,
405 * and the third is the user name.
407 argv[argc++] = command;
409 case PW_SU: argv[argc++] = "-s"; break;
410 case PW_LOGIN: argv[argc++] = "-l"; break;
411 case PW_ADD: argv[argc++] = "-a"; break;
412 case PW_CHANGE: argv[argc++] = "-c"; break;
413 case PW_DELETE: argv[argc++] = "-d"; break;
414 case PW_TELNET: argv[argc++] = "-t"; break;
415 case PW_RLOGIN: argv[argc++] = "-r"; break;
416 case PW_FTP: argv[argc++] = "-f"; break;
417 case PW_REXEC: argv[argc++] = "-x"; break;
419 if (reason == PW_CHANGE && input)
420 argv[argc++] = input;
423 argv[argc] = (char *) 0;
426 * The FTP and REXEC reasons use a pipe to communicate
427 * with the parent. The other standard I/O descriptors
428 * are closed and re-opened as /dev/null.
435 if (dup (pipes[0]) != 0)
441 if (open ("/dev/null", O_WRONLY) != 1)
444 if (open ("/dev/null", O_WRONLY) != 2)
449 * Now we execute the command directly.
450 * Do it with empty environment for safety. --marekm
452 execve(command, argv, &empty_env);
453 _exit((errno == ENOENT) ? 127 : 126);
457 * FTP and REXEC cause a single line of text to be
458 * sent to the child over a pipe that was set up
465 write (pipes[1], input, strlen (input));
467 write (pipes[1], "\n", 1);
472 * Wait on the child to die. When it does you will
473 * get the exit status and use that to determine if
474 * the authentication program was successful.
476 while ((i = wait (&status)) != pid && i != -1)
480 * Re-set the signals to their earlier values.
482 signal (SIGINT, sigint);
483 signal (SIGQUIT, sigquit);
485 signal (SIGTSTP, sigtstp);
489 * Make sure we found the right process!
503 * _builtin_auth - lookup routine in table and execute
507 _builtin_auth(const char *command, const char *user, int reason, const char *input)
512 * Scan the table, looking for a match. If we fall off
513 * the end, it must mean that this method isn't supported,
514 * so we fail the authentication.
517 for (i = 0;methods[i].name[0];i++) {
518 if (! strcmp (command, methods[i].name))
521 if (methods[i].name[0] == '\0')
525 * Call the pointed to function with the other three
529 return (methods[i].func) (user, reason, input);
531 #endif /* AUTH_METHODS */
534 * This function does the real work. It splits the list of program names
535 * up into individual programs and executes them one at a time.
539 pw_auth(const char *command, const char *user, int reason, const char *input)
547 * Quick little sanity check ...
550 if (strlen (command) >= sizeof buf)
553 strcpy(buf, command); /* safe (because of the above check) --marekm */
556 * Find each command and make sure it is NUL-terminated. Then
557 * invoke _pw_auth to actually run the program. The first
558 * failing program ends the whole mess.
561 for (cmd = buf;cmd;cmd = end) {
562 if ((end = strchr (cmd, ';')))
566 rc = _old_auth (cmd, user, reason, input);
567 else if (cmd[1] == '/')
568 rc = _pw_auth (cmd + 1, user, reason, input);
570 rc = _builtin_auth (cmd + 1, user, reason, input);
576 return _old_auth(command, user, reason, input);