| /* |
| * passprompt.c - pppd plugin to invoke an external PAP password prompter |
| * |
| * Copyright 1999 Paul Mackerras, Alan Curry. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version |
| * 2 of the License, or (at your option) any later version. |
| */ |
| #include <errno.h> |
| #include <unistd.h> |
| #include <sys/wait.h> |
| #include <syslog.h> |
| #include "pppd.h" |
| |
| char pppd_version[] = VERSION; |
| |
| static char promptprog[PATH_MAX+1]; |
| |
| static option_t options[] = { |
| { "promptprog", o_string, promptprog, |
| "External PAP password prompting program", |
| OPT_STATIC, NULL, PATH_MAX }, |
| { NULL } |
| }; |
| |
| static int promptpass(char *user, char *passwd) |
| { |
| int p[2]; |
| pid_t kid; |
| int readgood, wstat; |
| ssize_t red; |
| |
| if (promptprog[0] == 0 || access(promptprog, X_OK) < 0) |
| return -1; /* sorry, can't help */ |
| |
| if (!passwd) |
| return 1; |
| |
| if (pipe(p)) { |
| warn("Can't make a pipe for %s", promptprog); |
| return 0; |
| } |
| if ((kid = fork()) == (pid_t) -1) { |
| warn("Can't fork to run %s", promptprog); |
| close(p[0]); |
| close(p[1]); |
| return 0; |
| } |
| if (!kid) { |
| /* we are the child, exec the program */ |
| char *argv[4], fdstr[32]; |
| sys_close(); |
| closelog(); |
| close(p[0]); |
| seteuid(getuid()); |
| setegid(getgid()); |
| argv[0] = promptprog; |
| argv[1] = user; |
| argv[2] = remote_name; |
| sprintf(fdstr, "%d", p[1]); |
| argv[3] = fdstr; |
| argv[4] = 0; |
| execv(*argv, argv); |
| _exit(127); |
| } |
| |
| /* we are the parent, read the password from the pipe */ |
| close(p[1]); |
| readgood = 0; |
| do { |
| red = read(p[0], passwd + readgood, MAXSECRETLEN-1 - readgood); |
| if (red == 0) |
| break; |
| if (red < 0) { |
| if (errno == EINTR) |
| continue; |
| error("Can't read secret from %s: %m", promptprog); |
| readgood = -1; |
| break; |
| } |
| readgood += red; |
| } while (readgood < MAXSECRETLEN - 1); |
| passwd[readgood] = 0; |
| close(p[0]); |
| |
| /* now wait for child to exit */ |
| while (waitpid(kid, &wstat, 0) < 0) { |
| if (errno != EINTR) { |
| warn("error waiting for %s: %m", promptprog); |
| break; |
| } |
| } |
| |
| if (readgood < 0) |
| return 0; |
| if (!WIFEXITED(wstat)) |
| warn("%s terminated abnormally", promptprog); |
| if (WEXITSTATUS(wstat)) |
| warn("%s exited with code %d", promptprog, WEXITSTATUS(status)); |
| |
| return 1; |
| } |
| |
| void plugin_init(void) |
| { |
| add_options(options); |
| pap_passwd_hook = promptpass; |
| } |