Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * getpass.c - platform independent getpass function.
5 : *
6 : * Copyright (c) 2010-2012 Andreas Schneider <asn@samba.org>
7 : *
8 : * This program is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 3 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * This program is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License
19 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 :
24 : #include "system/filesys.h"
25 : #include "system/terminal.h"
26 :
27 : #if !defined(SMB_MALLOC)
28 : #undef malloc
29 : #define SMB_MALLOC(s) malloc((s))
30 : #endif
31 :
32 : /**
33 : * @internal
34 : *
35 : * @brief Get the password from the console.
36 : *
37 : * @param[in] prompt The prompt to display.
38 : *
39 : * @param[in] buf The buffer to fill.
40 : *
41 : * @param[in] len The length of the buffer.
42 : *
43 : * @param[in] verify Should the password be verified?
44 : *
45 : * @return 1 on success, 0 on error.
46 : */
47 80 : static int samba_gets(const char *prompt, char *buf, size_t len, bool verify)
48 : {
49 0 : char *tmp;
50 80 : char *ptr = NULL;
51 80 : int ok = 0;
52 :
53 80 : tmp = SMB_MALLOC(len);
54 80 : if (tmp == NULL) {
55 0 : return 0;
56 : }
57 80 : memset(tmp,'\0',len);
58 :
59 : /* read the password */
60 158 : while (!ok) {
61 80 : if (buf[0] != '\0') {
62 0 : fprintf(stdout, "%s[%s] ", prompt, buf);
63 : } else {
64 80 : fprintf(stdout, "%s", prompt);
65 : }
66 80 : fflush(stdout);
67 80 : if (fgets(tmp, len, stdin) == NULL) {
68 2 : free(tmp);
69 2 : return 0;
70 : }
71 :
72 78 : if ((ptr = strchr(tmp, '\n'))) {
73 78 : *ptr = '\0';
74 : }
75 78 : fprintf(stdout, "\n");
76 :
77 78 : if (*tmp) {
78 78 : strncpy(buf, tmp, len);
79 : }
80 :
81 78 : if (verify) {
82 0 : char *key_string;
83 :
84 0 : key_string = SMB_MALLOC(len);
85 0 : if (key_string == NULL) {
86 0 : break;
87 : }
88 0 : memset(key_string, '\0', len);
89 :
90 0 : fprintf(stdout, "\nVerifying, please re-enter. %s", prompt);
91 0 : fflush(stdout);
92 0 : if (! fgets(key_string, len, stdin)) {
93 0 : memset(key_string, '\0', len);
94 0 : SAFE_FREE(key_string);
95 0 : clearerr(stdin);
96 0 : continue;
97 : }
98 0 : if ((ptr = strchr(key_string, '\n'))) {
99 0 : *ptr = '\0';
100 : }
101 0 : fprintf(stdout, "\n");
102 0 : if (strcmp(buf, key_string)) {
103 0 : printf("\n\07\07Mismatch - try again\n");
104 0 : memset(key_string, '\0', len);
105 0 : SAFE_FREE(key_string);
106 0 : fflush(stdout);
107 0 : continue;
108 : }
109 0 : memset(key_string, '\0', len);
110 0 : SAFE_FREE(key_string);
111 : }
112 78 : ok = 1;
113 : }
114 78 : memset(tmp, '\0', len);
115 78 : free(tmp);
116 :
117 78 : return ok;
118 : }
119 :
120 : /**
121 : * @brief Get a password from the console.
122 : *
123 : * You should make sure that the buffer is an empty string!
124 : *
125 : * You can also use this function to ask for a username. Then you can fill the
126 : * buffer with the username and it is shows to the users. If the users just
127 : * presses enter the buffer will be untouched.
128 : *
129 : * @code
130 : * char username[128];
131 : *
132 : * snprintf(username, sizeof(username), "john");
133 : *
134 : * samba_getpass("Username:", username, sizeof(username), 1, 0);
135 : * @endcode
136 : *
137 : * The prompt will look like this:
138 : *
139 : * Username: [john]
140 : *
141 : * If you press enter then john is used as the username, or you can type it in
142 : * to change it.
143 : *
144 : * @param[in] prompt The prompt to show to ask for the password.
145 : *
146 : * @param[out] buf The buffer the password should be stored. It NEEDS to be
147 : * empty or filled out.
148 : *
149 : * @param[in] len The length of the buffer.
150 : *
151 : * @param[in] echo Should we echo what you type.
152 : *
153 : * @param[in] verify Should we ask for the password twice.
154 : *
155 : * @return 0 on success, -1 on error.
156 : */
157 80 : int samba_getpass(const char *prompt,
158 : char *buf,
159 : size_t len,
160 : bool echo,
161 : bool verify)
162 : {
163 0 : struct termios attr;
164 0 : struct termios old_attr;
165 80 : int ok = 0;
166 80 : int fd = -1;
167 :
168 : /* fgets needs at least len - 1 */
169 80 : if (prompt == NULL || buf == NULL || len < 2) {
170 0 : return -1;
171 : }
172 :
173 80 : if (isatty (STDIN_FILENO)) {
174 :
175 46 : ZERO_STRUCT(attr);
176 46 : ZERO_STRUCT(old_attr);
177 :
178 : /* get local terminal attributes */
179 46 : if (tcgetattr(STDIN_FILENO, &attr) < 0) {
180 0 : perror("tcgetattr");
181 0 : return -1;
182 : }
183 :
184 : /* save terminal attributes */
185 46 : memcpy(&old_attr, &attr, sizeof(attr));
186 46 : if((fd = fcntl(0, F_GETFL, 0)) < 0) {
187 0 : perror("fcntl");
188 0 : return -1;
189 : }
190 :
191 : /* disable echo */
192 46 : if (!echo) {
193 46 : attr.c_lflag &= ~(ECHO);
194 : }
195 :
196 : /* write attributes to terminal */
197 46 : if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) < 0) {
198 0 : perror("tcsetattr");
199 0 : return -1;
200 : }
201 : }
202 :
203 : /* disable nonblocking I/O */
204 80 : if (fd & O_NDELAY) {
205 34 : fcntl(0, F_SETFL, fd & ~O_NDELAY);
206 : }
207 :
208 80 : ok = samba_gets(prompt, buf, len, verify);
209 :
210 80 : if (isatty (STDIN_FILENO)) {
211 :
212 : /* reset terminal */
213 46 : tcsetattr(STDIN_FILENO, TCSANOW, &old_attr);
214 : }
215 :
216 : /* close fd */
217 80 : if (fd & O_NDELAY) {
218 34 : fcntl(0, F_SETFL, fd);
219 : }
220 :
221 80 : if (!ok) {
222 2 : memset (buf, '\0', len);
223 2 : return -1;
224 : }
225 :
226 : /* force termination */
227 78 : buf[len - 1] = '\0';
228 :
229 78 : return 0;
230 : }
|