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