]> git.ozlabs.org Git - ppp.git/blobdiff - contrib/pppgetpass/pppgetpass.vt.c
Get the repository a bit closer to what will be released
[ppp.git] / contrib / pppgetpass / pppgetpass.vt.c
diff --git a/contrib/pppgetpass/pppgetpass.vt.c b/contrib/pppgetpass/pppgetpass.vt.c
new file mode 100644 (file)
index 0000000..a152088
--- /dev/null
@@ -0,0 +1,218 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+#include <termios.h>
+#include <sys/vt.h>
+
+static int console_owner(uid_t, int);
+
+int main(int argc, char **argv)
+{
+  int console;
+  uid_t uid;
+  struct vt_stat origstate;
+  int openvtnum;
+  char openvtname[256];
+  int openvt;
+  gid_t gid;
+  int chowned;
+  FILE *fp;
+  struct termios t;
+  char pass[256], *nl;
+  int outfd, passlen;
+  ssize_t wrote;
+  console=open("/dev/console", O_RDWR);
+
+  uid=getuid();
+  gid=getgid();
+  seteuid(uid);
+
+  openlog(argv[0], LOG_PID, LOG_DAEMON);
+
+  if(argc!=4) {
+    syslog(LOG_WARNING, "Usage error");
+    return 1;
+  }
+
+  if(console<0) {
+    syslog(LOG_ERR, "open(/dev/console): %m");
+    return 1;
+  }
+
+  if(ioctl(console, VT_GETSTATE, &origstate)<0) {
+    syslog(LOG_ERR, "VT_GETSTATE: %m");
+    return 1;
+  }
+
+  if(uid) {
+    if(!console_owner(uid, origstate.v_active)) {
+      int i;
+      for(i=0;i<64;++i) {
+        if(i!=origstate.v_active && console_owner(uid, i))
+          break;
+      }
+      if(i==64) {
+        syslog(LOG_WARNING, "run by uid %lu not at console", (unsigned long)uid);
+        return 1;
+      }
+    }
+  }
+
+  if(ioctl(console, VT_OPENQRY, &openvtnum)<0) {
+    syslog(LOG_ERR, "VT_OPENQRY: %m");
+    return 1;
+  }
+  if(openvtnum==-1) {
+    syslog(LOG_ERR, "No free VTs");
+    return 1;
+  }
+
+  snprintf(openvtname, sizeof openvtname, "/dev/tty%d", openvtnum);
+  seteuid(0);
+  openvt=open(openvtname, O_RDWR);
+  if(openvt<0) {
+    seteuid(uid);
+    syslog(LOG_ERR, "open(%s): %m", openvtname);
+    return 1;
+  }
+
+  chowned=fchown(openvt, uid, gid);
+  if(chowned<0) {
+    seteuid(uid);
+    syslog(LOG_ERR, "fchown(%s): %m", openvtname);
+    return 1;
+  }
+
+  close(console);
+
+  if(ioctl(openvt, VT_ACTIVATE, openvtnum)<0) {
+    seteuid(uid);
+    syslog(LOG_ERR, "VT_ACTIVATE(%d): %m", openvtnum);
+    return 1;
+  }
+
+  while(ioctl(openvt, VT_WAITACTIVE, openvtnum)<0) {
+    if(errno!=EINTR) {
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      syslog(LOG_ERR, "VT_WAITACTIVE(%d): %m", openvtnum);
+      return 1;
+    }
+  }
+
+  seteuid(uid);
+  fp=fdopen(openvt, "r+");
+  if(!fp) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    syslog(LOG_ERR, "fdopen(%s): %m", openvtname);
+    return 1;
+  }
+
+  if(tcgetattr(openvt, &t)<0) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    syslog(LOG_ERR, "tcgetattr(%s): %m", openvtname);
+    return 1;
+  }
+  t.c_lflag &= ~ECHO;
+  if(tcsetattr(openvt, TCSANOW, &t)<0) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    syslog(LOG_ERR, "tcsetattr(%s): %m", openvtname);
+    return 1;
+  }
+
+  if(fprintf(fp, "\033[2J\033[H")<0) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    syslog(LOG_ERR, "write error on %s: %m", openvtname);
+    return 1;
+  }
+  if(argv[1][0] && argv[2][0]) {
+    if(fprintf(fp, "Password for PPP client %s on server %s: ", argv[1], argv[2])<0) {
+      seteuid(0);
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      syslog(LOG_ERR, "write error on %s: %m", openvtname);
+      return 1;
+    }
+  } else if(argv[1][0] && !argv[2][0]) {
+    if(fprintf(fp, "Password for PPP client %s: ", argv[1])<0) {
+      syslog(LOG_ERR, "write error on %s: %m", openvtname);
+      seteuid(0);
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      return 1;
+    }
+  } else if(!argv[1][0] && argv[2][0]) {
+    if(fprintf(fp, "Password for PPP on server %s: ", argv[2])<0) {
+      seteuid(0);
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      syslog(LOG_ERR, "write error on %s: %m", openvtname);
+      return 1;
+    }
+  } else {
+    if(fprintf(fp, "Enter PPP password: ")<0) {
+      seteuid(0);
+      ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+      seteuid(uid);
+      syslog(LOG_ERR, "write error on %s: %m", openvtname);
+      return 1;
+    }
+  }
+
+  if(!fgets(pass, sizeof pass, fp)) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    if(ferror(fp)) {
+      syslog(LOG_ERR, "read error on %s: %m", openvtname);
+    }
+    return 1;
+  }
+  if((nl=strchr(pass, '\n'))) 
+    *nl=0;
+  passlen=strlen(pass);
+  
+  outfd=atoi(argv[3]);
+  if((wrote=write(outfd, pass, passlen))!=passlen) {
+    seteuid(0);
+    ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+    seteuid(uid);
+    if(wrote<0)
+      syslog(LOG_ERR, "write error on outpipe: %m");
+    else
+      syslog(LOG_ERR, "short write on outpipe");
+    return 1;
+  }
+
+  seteuid(0);
+  ioctl(openvt, VT_ACTIVATE, origstate.v_active);
+  seteuid(uid);
+  return 0;
+}
+
+static int console_owner(uid_t uid, int cons)
+{
+  char name[256];
+  struct stat st;
+  snprintf(name, sizeof name, "/dev/tty%d", cons);
+  if(stat(name, &st)<0) {
+    if(errno!=ENOENT)
+      syslog(LOG_ERR, "stat(%s): %m", name);
+    return 0;
+  }
+  return uid==st.st_uid;
+}