1 /* 2 * passprompt.c - pppd plugin to invoke an external PAP password prompter 3 * 4 * Copyright 1999 Paul Mackerras, Alan Curry. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 #include <errno.h> 12 #include <unistd.h> 13 #include <sys/wait.h> 14 #include <syslog.h> 15 #include "pppd.h" 16 17 char pppd_version[] = VERSION; 18 19 static char promptprog[PATH_MAX+1]; 20 21 static option_t options[] = { 22 { "promptprog", o_string, promptprog, 23 "External PAP password prompting program", 24 OPT_STATIC, NULL, PATH_MAX }, 25 { NULL } 26 }; 27 28 static int promptpass(char *user, char *passwd) 29 { 30 int p[2]; 31 pid_t kid; 32 int readgood, wstat; 33 ssize_t red; 34 35 if (promptprog[0] == 0 || access(promptprog, X_OK) < 0) 36 return -1; /* sorry, can't help */ 37 38 if (!passwd) 39 return 1; 40 41 if (pipe(p)) { 42 warn("Can't make a pipe for %s", promptprog); 43 return 0; 44 } 45 if ((kid = fork()) == (pid_t) -1) { 46 warn("Can't fork to run %s", promptprog); 47 close(p[0]); 48 close(p[1]); 49 return 0; 50 } 51 if (!kid) { 52 /* we are the child, exec the program */ 53 char *argv[4], fdstr[32]; 54 sys_close(); 55 closelog(); 56 close(p[0]); 57 seteuid(getuid()); 58 setegid(getgid()); 59 argv[0] = promptprog; 60 argv[1] = user; 61 argv[2] = remote_name; 62 sprintf(fdstr, "%d", p[1]); 63 argv[3] = fdstr; 64 argv[4] = 0; 65 execv(*argv, argv); 66 _exit(127); 67 } 68 69 /* we are the parent, read the password from the pipe */ 70 close(p[1]); 71 readgood = 0; 72 do { 73 red = read(p[0], passwd + readgood, MAXSECRETLEN-1 - readgood); 74 if (red == 0) 75 break; 76 if (red < 0) { 77 if (errno == EINTR) 78 continue; 79 error("Can't read secret from %s: %m", promptprog); 80 readgood = -1; 81 break; 82 } 83 readgood += red; 84 } while (readgood < MAXSECRETLEN - 1); 85 passwd[readgood] = 0; 86 close(p[0]); 87 88 /* now wait for child to exit */ 89 while (waitpid(kid, &wstat, 0) < 0) { 90 if (errno != EINTR) { 91 warn("error waiting for %s: %m", promptprog); 92 break; 93 } 94 } 95 96 if (readgood < 0) 97 return 0; 98 if (!WIFEXITED(wstat)) 99 warn("%s terminated abnormally", promptprog); 100 if (WEXITSTATUS(wstat)) 101 warn("%s exited with code %d", promptprog, WEXITSTATUS(status)); 102 103 return 1; 104 } 105 106 void plugin_init(void) 107 { 108 add_options(options); 109 pap_passwd_hook = promptpass; 110 } 111