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 <fcntl.h> 14 #include <sys/wait.h> 15 #include <syslog.h> 16 #include "pppd.h" 17 18 static char promptprog[PATH_MAX+1]; 19 20 static option_t options[] = { 21 { "promptprog", o_string, promptprog, 22 "External PAP password prompting program", 23 OPT_STATIC, NULL, PATH_MAX }, 24 { NULL } 25 }; 26 27 static int promptpass(char *user, char *passwd) 28 { 29 int p[2]; 30 pid_t kid; 31 int readgood, wstat; 32 int red; 33 34 if (promptprog[0] == 0 || access(promptprog, X_OK) < 0) 35 return -1; /* sorry, can't help */ 36 37 /* This occurs when we're probed for the ability to supply a password */ 38 if (user != NULL && passwd == NULL) 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 (void) close(p[0]); 48 (void) close(p[1]); 49 return 0; 50 } 51 if (kid == (pid_t)0) { 52 /* we are the child, exec the program */ 53 char *argv[5], fdstr[32]; 54 55 sys_close(); 56 closelog(); 57 if (detached && p[1] <= 2) { 58 (void) dup2(p[1], 3); 59 p[1] = 3; 60 } 61 (void) close(p[0]); 62 if (detached) { 63 red = open("/etc/ppp/prompt-errors", O_WRONLY | O_APPEND | O_CREAT, 64 0600); 65 (void) dup2(red, 1); 66 (void) dup2(red, 2); 67 } 68 (void) seteuid(getuid()); 69 (void) setegid(getgid()); 70 argv[0] = promptprog; 71 argv[1] = user == NULL ? "" : user; 72 argv[2] = remote_name; 73 slprintf(fdstr, sizeof (fdstr), "%d", p[1]); 74 argv[3] = fdstr; 75 argv[4] = NULL; 76 (void) execv(*argv, argv); 77 _exit(127); 78 } 79 80 /* we are the parent, read the password from the pipe */ 81 (void) close(p[1]); 82 readgood = 0; 83 do { 84 red = read(p[0], passwd + readgood, MAXSECRETLEN-1 - readgood); 85 if (red == 0) 86 break; 87 if (red < 0) { 88 if (errno == EINTR) 89 continue; 90 error("Can't read secret from %s: %m", promptprog); 91 readgood = -1; 92 break; 93 } 94 readgood += red; 95 } while (readgood < MAXSECRETLEN - 1); 96 passwd[readgood] = 0; 97 (void) close(p[0]); 98 99 /* now wait for child to exit */ 100 while (waitpid(kid, &wstat, 0) < 0) { 101 if (errno != EINTR) { 102 warn("error waiting for %s: %m", promptprog); 103 break; 104 } 105 } 106 107 if (readgood < 0) 108 return 0; 109 if (readgood > 0 && passwd[--readgood] == '\n') 110 passwd[readgood] = '\0'; 111 if (!WIFEXITED(wstat)) 112 warn("%s terminated abnormally", promptprog); 113 if (WEXITSTATUS(wstat) != 0) 114 warn("%s exited with code %d", promptprog, WEXITSTATUS(wstat)); 115 116 return 1; 117 } 118 119 void plugin_init(void) 120 { 121 add_options(options); 122 pap_passwd_hook = promptpass; 123 }