summaryrefslogtreecommitdiff
path: root/usr.bin/ssh/readpass.c
blob: c9b37dd9b5f3e07260b5693897f5d32e8c1c114f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*

readpass.c

Author: Tatu Ylonen <ylo@cs.hut.fi>

Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                   All rights reserved

Created: Mon Jul 10 22:08:59 1995 ylo

Functions for reading passphrases and passwords.

*/

#include "includes.h"
RCSID("$Id: readpass.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $");

#include "xmalloc.h"
#include "ssh.h"

/* Saved old terminal mode for read_passphrase. */
#ifdef USING_TERMIOS
static struct termios saved_tio;
#endif
#ifdef USING_SGTTY
static struct sgttyb saved_tio;
#endif

/* Old interrupt signal handler for read_passphrase. */
static RETSIGTYPE (*old_handler)(int sig) = NULL;

/* Interrupt signal handler for read_passphrase. */

RETSIGTYPE intr_handler(int sig)
{
  /* Restore terminal modes. */
#ifdef USING_TERMIOS
  tcsetattr(fileno(stdin), TCSANOW, &saved_tio);
#endif
#ifdef USING_SGTTY
  ioctl(fileno(stdin), TIOCSETP, &saved_tio);
#endif
  /* Restore the old signal handler. */
  signal(sig, old_handler);
  /* Resend the signal, with the old handler. */
  kill(getpid(), sig);
}

/* Reads a passphrase from /dev/tty with echo turned off.  Returns the 
   passphrase (allocated with xmalloc).  Exits if EOF is encountered. 
   The passphrase if read from stdin if from_stdin is true (as is the
   case with ssh-keygen).  */

char *read_passphrase(const char *prompt, int from_stdin)
{
  char buf[1024], *cp;
#ifdef USING_TERMIOS
  struct termios tio;
#endif
#ifdef USING_SGTTY
  struct sgttyb tio;
#endif
  FILE *f;
  
  if (from_stdin)
    f = stdin;
  else
    {
      /* Read the passphrase from /dev/tty to make it possible to ask it even 
	 when stdin has been redirected. */
      f = fopen("/dev/tty", "r");
      if (!f)
	{
	  if (getenv("DISPLAY"))
	    {
	      char command[512];
	      fprintf(stderr,
		      "Executing ssh-askpass to query the password...\n");
	      fflush(stdout);
	      fflush(stderr);
	      sprintf(command, "ssh-askpass '%.400s'", prompt);
	      f = popen(command, "r");
	      if (!fgets(buf, sizeof(buf), f))
		{
		  pclose(f);
		  fprintf(stderr, "No passphrase supplied.  Exiting.\n");
		  exit(1);
		}
	      pclose(f);
	      if (strchr(buf, '\n'))
		*strchr(buf, '\n') = 0;
	      return xstrdup(buf);
	    }

	  /* No controlling terminal and no DISPLAY.  Nowhere to read. */
	  fprintf(stderr, "You have no controlling tty and no DISPLAY.  Cannot read passphrase.\n");
	  exit(1);
	}
    }

  /* Display the prompt (on stderr because stdout might be redirected). */
  fflush(stdout);
  fprintf(stderr, "%s", prompt);
  fflush(stderr);

  /* Get terminal modes. */
#ifdef USING_TERMIOS
  tcgetattr(fileno(f), &tio);
#endif
#ifdef USING_SGTTY
  ioctl(fileno(f), TIOCGETP, &tio);
#endif
  saved_tio = tio;
  /* Save signal handler and set the new handler. */
  old_handler = signal(SIGINT, intr_handler);

  /* Set new terminal modes disabling all echo. */
#ifdef USING_TERMIOS
  tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
  tcsetattr(fileno(f), TCSANOW, &tio);
#endif
#ifdef USING_SGTTY
  tio.sg_flags &= ~(ECHO);
  ioctl(fileno(f), TIOCSETP, &tio);
#endif

  /* Read the passphrase from the terminal. */
  if (fgets(buf, sizeof(buf), f) == NULL)
    {
      /* Got EOF.  Just exit. */
      /* Restore terminal modes. */
#ifdef USING_TERMIOS
      tcsetattr(fileno(f), TCSANOW, &saved_tio);
#endif
#ifdef USING_SGTTY
      ioctl(fileno(f), TIOCSETP, &saved_tio);
#endif
      /* Restore the signal handler. */
      signal(SIGINT, old_handler);
      /* Print a newline (the prompt probably didn\'t have one). */
      fprintf(stderr, "\n");
      /* Close the file. */
      if (f != stdin)
	fclose(f);
      exit(1);
    }
  /* Restore terminal modes. */
#ifdef USING_TERMIOS
  tcsetattr(fileno(f), TCSANOW, &saved_tio);
#endif
#ifdef USING_SGTTY
  ioctl(fileno(f), TIOCSETP, &saved_tio);
#endif
  /* Restore the signal handler. */
  (void)signal(SIGINT, old_handler);
  /* Remove newline from the passphrase. */
  if (strchr(buf, '\n'))
    *strchr(buf, '\n') = 0;
  /* Allocate a copy of the passphrase. */
  cp = xstrdup(buf);
  /* Clear the buffer so we don\'t leave copies of the passphrase laying
     around. */
  memset(buf, 0, sizeof(buf));
  /* Print a newline since the prompt probably didn\'t have one. */
  fprintf(stderr, "\n");
  /* Close the file. */
  if (f != stdin)
    fclose(f);
  return cp;
}