comparison svr-auth.c @ 808:d7784616409a

improve auth failure delays to avoid indicating which users exist
author Matt Johnston <matt@ucc.asn.au>
date Sun, 26 May 2013 18:39:24 +0800
parents e0084f136cb8
children 8fe36617bf4e
comparison
equal deleted inserted replaced
782:e0084f136cb8 808:d7784616409a
108 * checking, and handle success or failure */ 108 * checking, and handle success or failure */
109 void recv_msg_userauth_request() { 109 void recv_msg_userauth_request() {
110 110
111 unsigned char *username = NULL, *servicename = NULL, *methodname = NULL; 111 unsigned char *username = NULL, *servicename = NULL, *methodname = NULL;
112 unsigned int userlen, servicelen, methodlen; 112 unsigned int userlen, servicelen, methodlen;
113 int valid_user = 0;
113 114
114 TRACE(("enter recv_msg_userauth_request")) 115 TRACE(("enter recv_msg_userauth_request"))
115 116
116 /* ignore packets if auth is already done */ 117 /* ignore packets if auth is already done */
117 if (ses.authstate.authdone == 1) { 118 if (ses.authstate.authdone == 1) {
122 /* send the banner if it exists, it will only exist once */ 123 /* send the banner if it exists, it will only exist once */
123 if (svr_opts.banner) { 124 if (svr_opts.banner) {
124 send_msg_userauth_banner(); 125 send_msg_userauth_banner();
125 } 126 }
126 127
127
128 username = buf_getstring(ses.payload, &userlen); 128 username = buf_getstring(ses.payload, &userlen);
129 servicename = buf_getstring(ses.payload, &servicelen); 129 servicename = buf_getstring(ses.payload, &servicelen);
130 methodname = buf_getstring(ses.payload, &methodlen); 130 methodname = buf_getstring(ses.payload, &methodlen);
131 131
132 /* only handle 'ssh-connection' currently */ 132 /* only handle 'ssh-connection' currently */
139 m_free(servicename); 139 m_free(servicename);
140 m_free(methodname); 140 m_free(methodname);
141 dropbear_exit("unknown service in auth"); 141 dropbear_exit("unknown service in auth");
142 } 142 }
143 143
144 /* check username is good before continuing */ 144 /* check username is good before continuing.
145 if (checkusername(username, userlen) == DROPBEAR_FAILURE) { 145 * the 'incrfail' varies depending on the auth method to
146 /* username is invalid/no shell/etc - send failure */ 146 * avoid giving away which users exist on the system through
147 TRACE(("sending checkusername failure")) 147 * the time delay. */
148 send_msg_userauth_failure(0, 1); 148 if (checkusername(username, userlen) == DROPBEAR_SUCCESS) {
149 goto out; 149 valid_user = 1;
150 } 150 }
151 151
152 /* user wants to know what methods are supported */ 152 /* user wants to know what methods are supported */
153 if (methodlen == AUTH_METHOD_NONE_LEN && 153 if (methodlen == AUTH_METHOD_NONE_LEN &&
154 strncmp(methodname, AUTH_METHOD_NONE, 154 strncmp(methodname, AUTH_METHOD_NONE,
155 AUTH_METHOD_NONE_LEN) == 0) { 155 AUTH_METHOD_NONE_LEN) == 0) {
156 TRACE(("recv_msg_userauth_request: 'none' request")) 156 TRACE(("recv_msg_userauth_request: 'none' request"))
157 if (svr_opts.allowblankpass 157 if (valid_user
158 && svr_opts.allowblankpass
158 && !svr_opts.noauthpass 159 && !svr_opts.noauthpass
159 && !(svr_opts.norootpass && ses.authstate.pw_uid == 0) 160 && !(svr_opts.norootpass && ses.authstate.pw_uid == 0)
160 && ses.authstate.pw_passwd[0] == '\0') 161 && ses.authstate.pw_passwd[0] == '\0')
161 { 162 {
162 dropbear_log(LOG_NOTICE, 163 dropbear_log(LOG_NOTICE,
166 send_msg_userauth_success(); 167 send_msg_userauth_success();
167 goto out; 168 goto out;
168 } 169 }
169 else 170 else
170 { 171 {
172 /* 'none' has no failure delay */
171 send_msg_userauth_failure(0, 0); 173 send_msg_userauth_failure(0, 0);
172 goto out; 174 goto out;
173 } 175 }
174 } 176 }
175 177
178 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { 180 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) {
179 /* user wants to try password auth */ 181 /* user wants to try password auth */
180 if (methodlen == AUTH_METHOD_PASSWORD_LEN && 182 if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
181 strncmp(methodname, AUTH_METHOD_PASSWORD, 183 strncmp(methodname, AUTH_METHOD_PASSWORD,
182 AUTH_METHOD_PASSWORD_LEN) == 0) { 184 AUTH_METHOD_PASSWORD_LEN) == 0) {
183 svr_auth_password(); 185 if (valid_user) {
184 goto out; 186 svr_auth_password();
187 goto out;
188 }
185 } 189 }
186 } 190 }
187 #endif 191 #endif
188 192
189 #ifdef ENABLE_SVR_PAM_AUTH 193 #ifdef ENABLE_SVR_PAM_AUTH
191 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { 195 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) {
192 /* user wants to try password auth */ 196 /* user wants to try password auth */
193 if (methodlen == AUTH_METHOD_PASSWORD_LEN && 197 if (methodlen == AUTH_METHOD_PASSWORD_LEN &&
194 strncmp(methodname, AUTH_METHOD_PASSWORD, 198 strncmp(methodname, AUTH_METHOD_PASSWORD,
195 AUTH_METHOD_PASSWORD_LEN) == 0) { 199 AUTH_METHOD_PASSWORD_LEN) == 0) {
196 svr_auth_pam(); 200 if (valid_user) {
197 goto out; 201 svr_auth_pam();
202 goto out;
203 }
198 } 204 }
199 } 205 }
200 #endif 206 #endif
201 207
202 #ifdef ENABLE_SVR_PUBKEY_AUTH 208 #ifdef ENABLE_SVR_PUBKEY_AUTH
203 /* user wants to try pubkey auth */ 209 /* user wants to try pubkey auth */
204 if (methodlen == AUTH_METHOD_PUBKEY_LEN && 210 if (methodlen == AUTH_METHOD_PUBKEY_LEN &&
205 strncmp(methodname, AUTH_METHOD_PUBKEY, 211 strncmp(methodname, AUTH_METHOD_PUBKEY,
206 AUTH_METHOD_PUBKEY_LEN) == 0) { 212 AUTH_METHOD_PUBKEY_LEN) == 0) {
207 svr_auth_pubkey(); 213 if (valid_user) {
214 svr_auth_pubkey();
215 } else {
216 /* pubkey has no failure delay */
217 send_msg_userauth_failure(0, 0);
218 }
208 goto out; 219 goto out;
209 } 220 }
210 #endif 221 #endif
211 222
212 /* nothing matched, we just fail */ 223 /* nothing matched, we just fail with a delay */
213 send_msg_userauth_failure(0, 1); 224 send_msg_userauth_failure(0, 1);
214 225
215 out: 226 out:
216 227
217 m_free(username); 228 m_free(username);
250 if (!ses.authstate.pw_name) { 261 if (!ses.authstate.pw_name) {
251 TRACE(("leave checkusername: user '%s' doesn't exist", username)) 262 TRACE(("leave checkusername: user '%s' doesn't exist", username))
252 dropbear_log(LOG_WARNING, 263 dropbear_log(LOG_WARNING,
253 "Login attempt for nonexistent user from %s", 264 "Login attempt for nonexistent user from %s",
254 svr_ses.addrstring); 265 svr_ses.addrstring);
255 send_msg_userauth_failure(0, 1);
256 return DROPBEAR_FAILURE; 266 return DROPBEAR_FAILURE;
257 } 267 }
258 268
259 /* check if we are running as non-root, and login user is different from the server */ 269 /* check if we are running as non-root, and login user is different from the server */
260 uid = geteuid(); 270 uid = geteuid();
262 TRACE(("running as nonroot, only server uid is allowed")) 272 TRACE(("running as nonroot, only server uid is allowed"))
263 dropbear_log(LOG_WARNING, 273 dropbear_log(LOG_WARNING,
264 "Login attempt with wrong user %s from %s", 274 "Login attempt with wrong user %s from %s",
265 ses.authstate.pw_name, 275 ses.authstate.pw_name,
266 svr_ses.addrstring); 276 svr_ses.addrstring);
267 send_msg_userauth_failure(0, 1);
268 return DROPBEAR_FAILURE; 277 return DROPBEAR_FAILURE;
269 } 278 }
270 279
271 /* check for non-root if desired */ 280 /* check for non-root if desired */
272 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { 281 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) {
273 TRACE(("leave checkusername: root login disabled")) 282 TRACE(("leave checkusername: root login disabled"))
274 dropbear_log(LOG_WARNING, "root login rejected"); 283 dropbear_log(LOG_WARNING, "root login rejected");
275 send_msg_userauth_failure(0, 1);
276 return DROPBEAR_FAILURE; 284 return DROPBEAR_FAILURE;
277 } 285 }
278 286
279 TRACE(("shell is %s", ses.authstate.pw_shell)) 287 TRACE(("shell is %s", ses.authstate.pw_shell))
280 288
299 /* no matching shell */ 307 /* no matching shell */
300 endusershell(); 308 endusershell();
301 TRACE(("no matching shell")) 309 TRACE(("no matching shell"))
302 dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", 310 dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
303 ses.authstate.pw_name); 311 ses.authstate.pw_name);
304 send_msg_userauth_failure(0, 1);
305 return DROPBEAR_FAILURE; 312 return DROPBEAR_FAILURE;
306 313
307 goodshell: 314 goodshell:
308 endusershell(); 315 endusershell();
309 TRACE(("matching shell")) 316 TRACE(("matching shell"))
310 317
311 TRACE(("uid = %d", ses.authstate.pw_uid)) 318 TRACE(("uid = %d", ses.authstate.pw_uid))
312 TRACE(("leave checkusername")) 319 TRACE(("leave checkusername"))
313 return DROPBEAR_SUCCESS; 320 return DROPBEAR_SUCCESS;
314
315 } 321 }
316 322
317 /* Send a failure message to the client, in responds to a userauth_request. 323 /* Send a failure message to the client, in responds to a userauth_request.
318 * Partial indicates whether to set the "partial success" flag, 324 * Partial indicates whether to set the "partial success" flag,
319 * incrfail is whether to count this failure in the failure count (which 325 * incrfail is whether to count this failure in the failure count (which
356 encrypt_packet(); 362 encrypt_packet();
357 363
358 if (incrfail) { 364 if (incrfail) {
359 unsigned int delay; 365 unsigned int delay;
360 genrandom((unsigned char*)&delay, sizeof(delay)); 366 genrandom((unsigned char*)&delay, sizeof(delay));
361 /* We delay for 300ms +- 50ms, 0.1ms granularity */ 367 /* We delay for 300ms +- 50ms */
362 delay = 250000 + (delay % 1000)*100; 368 delay = 250000 + (delay % 100000);
363 usleep(delay); 369 usleep(delay);
364 ses.authstate.failcount++; 370 ses.authstate.failcount++;
365 } 371 }
366 372
367 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { 373 if (ses.authstate.failcount >= MAX_AUTH_TRIES) {