Branch data Line data Source code
1 : : /*
2 : : *****************************************************************************
3 : : *
4 : : * File: getpasswd.c
5 : : *
6 : : * Purpose: Routines for obtaining a password from a user.
7 : : *
8 : : * Fwknop is developed primarily by the people listed in the file 'AUTHORS'.
9 : : * Copyright (C) 2009-2014 fwknop developers and contributors. For a full
10 : : * list of contributors, see the file 'CREDITS'.
11 : : *
12 : : * License (GNU General Public License):
13 : : *
14 : : * This program is free software; you can redistribute it and/or
15 : : * modify it under the terms of the GNU General Public License
16 : : * as published by the Free Software Foundation; either version 2
17 : : * of the License, or (at your option) any later version.
18 : : *
19 : : * This program is distributed in the hope that it will be useful,
20 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 : : * GNU General Public License for more details.
23 : : *
24 : : * You should have received a copy of the GNU General Public License
25 : : * along with this program; if not, write to the Free Software
26 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 : : * USA
28 : : *
29 : : *****************************************************************************
30 : : */
31 : : #include <stdio.h>
32 : : #include <signal.h>
33 : :
34 : : #ifdef WIN32
35 : : #include <conio.h>
36 : : #else
37 : : #include <termios.h>
38 : : #endif
39 : :
40 : : #include "fwknop_common.h"
41 : : #include "getpasswd.h"
42 : : #include "utils.h"
43 : :
44 : : #define PW_BUFSIZE 128 /*!< Maximum number of chars an encryption key or a password can contain */
45 : :
46 : : #define PW_BREAK_CHAR 0x03 /*!< Ascii code for the Ctrl-C char */
47 : : #define PW_BS_CHAR 0x08 /*!< Ascii code for the backspace char */
48 : : #define PW_LF_CHAR 0x0A /*!< Ascii code for the \n char */
49 : : #define PW_CR_CHAR 0x0D /*!< Ascii code for the \r char */
50 : : #define PW_CLEAR_CHAR 0x15 /*!< Ascii code for the Ctrl-U char */
51 : :
52 : : #define ARRAY_FIRST_ELT_ADR(t) &((t)[0]) /*!< Macro to get the first element of an array */
53 : : #define ARRAY_LAST_ELT_ADR(t) &((t)[sizeof(t)-1]) /*!< Macro to get the last element of an array */
54 : :
55 : : /**
56 : : * @brief Read a password from a stream object
57 : : *
58 : : * @param stream Pointer to a FILE object that identifies an input stream.
59 : : *
60 : : * @return The password buffer or NULL if not set
61 : : */
62 : : static char *
63 : 9 : read_passwd_from_stream(FILE *stream)
64 : : {
65 : : static char password[PW_BUFSIZE] = {0};
66 : : int c;
67 : : char *ptr;
68 : :
69 : 9 : ptr = ARRAY_FIRST_ELT_ADR(password);
70 : :
71 [ + - ]: 9 : if(stream == NULL)
72 : : return password;
73 : :
74 : : #ifdef WIN32
75 : : while((c = _getch()) != PW_CR_CHAR)
76 : : #else
77 [ + - ][ + + ]: 77 : while( ((c = getc(stream)) != EOF) && (c != PW_LF_CHAR) && (c != PW_BREAK_CHAR) )
78 : : #endif
79 : : {
80 : : /* Handle a backspace without backing up too far. */
81 [ - + ]: 68 : if (c == PW_BS_CHAR)
82 : : {
83 [ # # ]: 0 : if (ptr != ARRAY_FIRST_ELT_ADR(password))
84 : 0 : ptr--;
85 : : }
86 : :
87 : : /* Handle a Ctrl-U to clear the password entry and start over */
88 [ + - ]: 68 : else if (c == PW_CLEAR_CHAR)
89 : : ptr = ARRAY_FIRST_ELT_ADR(password);
90 : :
91 : : /* Fill in the password buffer until it reaches the last -1 char.
92 : : * The last char is used to NULL terminate the string. */
93 [ + - ]: 68 : else if (ptr < ARRAY_LAST_ELT_ADR(password))
94 : : {
95 : 68 : *ptr++ = c;
96 : : }
97 : :
98 : : /* Discard char */
99 : : else;
100 : : }
101 : :
102 : : /* A CTRL-C char has been detected, we discard the password */
103 [ - + ]: 9 : if (c == PW_BREAK_CHAR)
104 : 0 : password[0] = '\0';
105 : :
106 : : /* Otherwise we NULL terminate the string here. Overflows are handled
107 : : * previously, so we can add the char without worrying */
108 : : else
109 : 9 : *ptr = '\0';
110 : :
111 : : return password;
112 : : }
113 : :
114 : : /**
115 : : * @brief Function for accepting password input from users
116 : : *
117 : : * The functions reads chars from a buffered stream and store them in a buffer of
118 : : * chars. If a file descriptor is supplied then, the password is read from
119 : : * the associated stream, otherwise a new buffered stream is created and a
120 : : * prompt is displayed to the user.
121 : : *
122 : : * @param prompt String displayed on the terminal to prompt the user for a
123 : : * password or an encryption key
124 : : * @param fd File descriptor to use to read the pasword from. If fd is set
125 : : * to FD_INVALID, then a new stream is opened.
126 : : *
127 : : * @return NULL if a problem occured or the user killed the terminal (Ctrl-C)\n
128 : : * otherwise the password - empty password is accepted.
129 : : */
130 : : char*
131 : 9 : getpasswd(const char *prompt, int fd)
132 : : {
133 : 9 : char *ptr = NULL;
134 : 9 : FILE *fp = NULL;
135 : :
136 : : #ifndef WIN32
137 : : sigset_t sig, old_sig;
138 : : struct termios ts;
139 : 9 : tcflag_t old_c_lflag = 0;
140 : : #else
141 : : /* Force stdin on windows. */
142 : : fd = 0;
143 : : #endif
144 : :
145 : : /* If a valid file descriptor is supplied, we try to open a stream from it */
146 [ - + ]: 9 : if (FD_IS_VALID(fd))
147 : : {
148 : 0 : fp = fdopen(fd, "r");
149 [ # # ]: 0 : if (fp == NULL)
150 : : {
151 : 0 : log_msg(LOG_VERBOSITY_ERROR, "getpasswd() - "
152 : : "Unable to create a stream from the file descriptor : %s",
153 : 0 : strerror(errno));
154 : 0 : return(NULL);
155 : : }
156 : : }
157 : :
158 : : #ifndef WIN32
159 : : /* Otherwise we are going to open a new stream */
160 : : else
161 : : {
162 [ + - ]: 9 : if((fp = fopen(ctermid(NULL), "r+")) == NULL)
163 : : return(NULL);
164 : :
165 : 9 : setbuf(fp, NULL);
166 : :
167 : : /* Setup blocks for SIGINT and SIGTSTP and save the original signal
168 : : * mask.
169 : : */
170 : 9 : sigemptyset(&sig);
171 : 9 : sigaddset(&sig, SIGINT);
172 : 9 : sigaddset(&sig, SIGTSTP);
173 : 9 : sigprocmask(SIG_BLOCK, &sig, &old_sig);
174 : :
175 : : /*
176 : : * Save current tty state for later restoration after we :
177 : : * - disable echo of characters to the tty
178 : : * - disable signal generation
179 : : * - disable cannonical mode (input read line by line mode)
180 : : */
181 : 9 : tcgetattr(fileno(fp), &ts);
182 : 9 : old_c_lflag = ts.c_lflag;
183 : 9 : ts.c_lflag &= ~(ECHO | ICANON | ISIG);
184 : 9 : tcsetattr(fileno(fp), TCSAFLUSH, &ts);
185 : :
186 : 9 : fputs(prompt, fp);
187 : : }
188 : : #else
189 : : _cputs(prompt);
190 : : #endif
191 : : /* Read the password */
192 : 9 : ptr = read_passwd_from_stream(fp);
193 : :
194 : : #ifdef WIN32
195 : : /* In Windows, it would be a CR-LF
196 : : */
197 : : _putch(PW_CR_CHAR);
198 : : _putch(PW_LF_CHAR);
199 : : #else
200 [ + - ]: 9 : if(! FD_IS_VALID(fd))
201 : : {
202 : : /* Reset terminal settings
203 : : */
204 : 9 : fputs("\n", fp);
205 : 9 : ts.c_lflag = old_c_lflag;
206 : 9 : tcsetattr(fileno(fp), TCSAFLUSH, &ts);
207 : : }
208 : : #endif
209 : :
210 : 9 : fclose(fp);
211 : :
212 : 9 : return (ptr);
213 : : }
214 : :
215 : : /* Function for accepting password input from a file
216 : : */
217 : : int
218 : 2 : get_key_file(char *key, int *key_len, const char *key_file,
219 : : fko_ctx_t ctx, const fko_cli_options_t *options)
220 : : {
221 : : FILE *pwfile_ptr;
222 : 2 : unsigned int numLines = 0, i = 0, found_dst;
223 : :
224 : 2 : char conf_line_buf[MAX_LINE_LEN] = {0};
225 : 2 : char tmp_char_buf[MAX_LINE_LEN] = {0};
226 : : char *lptr;
227 : :
228 : : memset(key, 0x00, MAX_KEY_LEN+1);
229 : :
230 [ + + ]: 2 : if ((pwfile_ptr = fopen(key_file, "r")) == NULL)
231 : : {
232 : 1 : log_msg(LOG_VERBOSITY_ERROR, "Could not open config file: %s", key_file);
233 : 1 : return 0;
234 : : }
235 : :
236 [ - + ]: 1 : while ((fgets(conf_line_buf, MAX_LINE_LEN, pwfile_ptr)) != NULL)
237 : : {
238 : 0 : numLines++;
239 : 0 : conf_line_buf[MAX_LINE_LEN-1] = '\0';
240 : 0 : lptr = conf_line_buf;
241 : :
242 : : memset(tmp_char_buf, 0x0, MAX_LINE_LEN);
243 : :
244 [ # # ][ # # ]: 0 : while (*lptr == ' ' || *lptr == '\t' || *lptr == '=')
245 : 0 : lptr++;
246 : :
247 : : /* Get past comments and empty lines.
248 : : */
249 [ # # ][ # # ]: 0 : if (*lptr == '#' || *lptr == '\n' || *lptr == '\r' || *lptr == '\0' || *lptr == ';')
[ # # ][ # # ]
250 : 0 : continue;
251 : :
252 : : /* Look for a line like "<SPA destination IP>: <password>" - this allows
253 : : * multiple keys to be placed within the same file, and the client will
254 : : * reference the matching one for the SPA server we are contacting
255 : : */
256 : : found_dst = 1;
257 [ # # ]: 0 : for (i=0; i < strlen(options->spa_server_str); i++)
258 [ # # ]: 0 : if (*lptr++ != options->spa_server_str[i])
259 : 0 : found_dst = 0;
260 : :
261 [ # # ]: 0 : if (! found_dst)
262 : 0 : continue;
263 : :
264 [ # # ]: 0 : if (*lptr == ':')
265 : 0 : lptr++;
266 : : else
267 : 0 : continue;
268 : :
269 : : /* Skip whitespace until we get to the password
270 : : */
271 [ # # ][ # # ]: 0 : while (*lptr == ' ' || *lptr == '\t' || *lptr == '=')
272 : 0 : lptr++;
273 : :
274 : : i = 0;
275 [ # # ]: 0 : while (*lptr != '\0' && *lptr != '\n') {
276 : 0 : key[i] = *lptr;
277 : 0 : lptr++;
278 : 0 : i++;
279 : : }
280 : 0 : key[i] = '\0';
281 : : }
282 : :
283 : 1 : fclose(pwfile_ptr);
284 : :
285 [ + - ]: 1 : if (key[0] == '\0') {
286 : 1 : log_msg(LOG_VERBOSITY_ERROR, "Could not get key for IP: %s from: %s",
287 : 1 : options->spa_server_str, key_file);
288 : 1 : return 0;
289 : : }
290 : :
291 : 0 : *key_len = strlen(key);
292 : :
293 : 0 : return 1;
294 : : }
295 : :
296 : : /***EOF***/
|