/src/samba/lib/util/getpass.c
Line | Count | Source |
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 | 0 | #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 | | static int samba_gets(const char *prompt, char *buf, size_t len, bool verify) |
48 | 0 | { |
49 | 0 | char *tmp; |
50 | 0 | char *ptr = NULL; |
51 | 0 | int ok = 0; |
52 | |
|
53 | 0 | tmp = SMB_MALLOC(len); |
54 | 0 | if (tmp == NULL) { |
55 | 0 | return 0; |
56 | 0 | } |
57 | 0 | memset(tmp,'\0',len); |
58 | | |
59 | | /* read the password */ |
60 | 0 | while (!ok) { |
61 | 0 | if (buf[0] != '\0') { |
62 | 0 | fprintf(stdout, "%s[%s] ", prompt, buf); |
63 | 0 | } else { |
64 | 0 | fprintf(stdout, "%s", prompt); |
65 | 0 | } |
66 | 0 | fflush(stdout); |
67 | 0 | if (fgets(tmp, len, stdin) == NULL) { |
68 | 0 | free(tmp); |
69 | 0 | return 0; |
70 | 0 | } |
71 | | |
72 | 0 | if ((ptr = strchr(tmp, '\n'))) { |
73 | 0 | *ptr = '\0'; |
74 | 0 | } |
75 | 0 | fprintf(stdout, "\n"); |
76 | |
|
77 | 0 | if (*tmp) { |
78 | 0 | strncpy(buf, tmp, len); |
79 | 0 | } |
80 | |
|
81 | 0 | 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 | 0 | } |
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 | 0 | } |
98 | 0 | if ((ptr = strchr(key_string, '\n'))) { |
99 | 0 | *ptr = '\0'; |
100 | 0 | } |
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 | 0 | } |
109 | 0 | memset(key_string, '\0', len); |
110 | 0 | SAFE_FREE(key_string); |
111 | 0 | } |
112 | 0 | ok = 1; |
113 | 0 | } |
114 | 0 | memset(tmp, '\0', len); |
115 | 0 | free(tmp); |
116 | |
|
117 | 0 | return ok; |
118 | 0 | } |
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 | | int samba_getpass(const char *prompt, |
158 | | char *buf, |
159 | | size_t len, |
160 | | bool echo, |
161 | | bool verify) |
162 | 0 | { |
163 | 0 | struct termios attr; |
164 | 0 | struct termios old_attr; |
165 | 0 | int ok = 0; |
166 | 0 | int fd = -1; |
167 | | |
168 | | /* fgets needs at least len - 1 */ |
169 | 0 | if (prompt == NULL || buf == NULL || len < 2) { |
170 | 0 | return -1; |
171 | 0 | } |
172 | | |
173 | 0 | if (isatty (STDIN_FILENO)) { |
174 | |
|
175 | 0 | ZERO_STRUCT(attr); |
176 | 0 | ZERO_STRUCT(old_attr); |
177 | | |
178 | | /* get local terminal attributes */ |
179 | 0 | if (tcgetattr(STDIN_FILENO, &attr) < 0) { |
180 | 0 | perror("tcgetattr"); |
181 | 0 | return -1; |
182 | 0 | } |
183 | | |
184 | | /* save terminal attributes */ |
185 | 0 | memcpy(&old_attr, &attr, sizeof(attr)); |
186 | 0 | if((fd = fcntl(0, F_GETFL, 0)) < 0) { |
187 | 0 | perror("fcntl"); |
188 | 0 | return -1; |
189 | 0 | } |
190 | | |
191 | | /* disable echo */ |
192 | 0 | if (!echo) { |
193 | 0 | attr.c_lflag &= ~(ECHO); |
194 | 0 | } |
195 | | |
196 | | /* write attributes to terminal */ |
197 | 0 | if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) < 0) { |
198 | 0 | perror("tcsetattr"); |
199 | 0 | return -1; |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | | /* disable nonblocking I/O */ |
204 | 0 | if (fd & O_NDELAY) { |
205 | 0 | fcntl(0, F_SETFL, fd & ~O_NDELAY); |
206 | 0 | } |
207 | |
|
208 | 0 | ok = samba_gets(prompt, buf, len, verify); |
209 | |
|
210 | 0 | if (isatty (STDIN_FILENO)) { |
211 | | |
212 | | /* reset terminal */ |
213 | 0 | tcsetattr(STDIN_FILENO, TCSANOW, &old_attr); |
214 | 0 | } |
215 | | |
216 | | /* close fd */ |
217 | 0 | if (fd & O_NDELAY) { |
218 | 0 | fcntl(0, F_SETFL, fd); |
219 | 0 | } |
220 | |
|
221 | 0 | if (!ok) { |
222 | 0 | memset (buf, '\0', len); |
223 | 0 | return -1; |
224 | 0 | } |
225 | | |
226 | | /* force termination */ |
227 | 0 | buf[len - 1] = '\0'; |
228 | |
|
229 | 0 | return 0; |
230 | 0 | } |