Home | History | Annotate | Download | only in plugins
      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[5], 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     close(p[0]);
     86 
     87     /* now wait for child to exit */
     88     while (waitpid(kid, &wstat, 0) < 0) {
     89 	if (errno != EINTR) {
     90 	    warn("error waiting for %s: %m", promptprog);
     91 	    break;
     92 	}
     93     }
     94 
     95     if (readgood < 0)
     96 	return 0;
     97     passwd[readgood] = 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