Mercurial > dropbear
comparison svr-auth.c @ 835:4095b6d7c9fc ecc
Merge in changes from the past couple of releases
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 18 Oct 2013 21:38:01 +0800 |
parents | 7dcb46da72d9 8fe36617bf4e |
children | 7540c0822374 |
comparison
equal
deleted
inserted
replaced
807:75509065db53 | 835:4095b6d7c9fc |
---|---|
35 #include "runopts.h" | 35 #include "runopts.h" |
36 #include "random.h" | 36 #include "random.h" |
37 | 37 |
38 static void authclear(); | 38 static void authclear(); |
39 static int checkusername(unsigned char *username, unsigned int userlen); | 39 static int checkusername(unsigned char *username, unsigned int userlen); |
40 static void send_msg_userauth_banner(); | |
41 | 40 |
42 /* initialise the first time for a session, resetting all parameters */ | 41 /* initialise the first time for a session, resetting all parameters */ |
43 void svr_authinitialise() { | 42 void svr_authinitialise() { |
44 | 43 |
45 ses.authstate.failcount = 0; | 44 ses.authstate.failcount = 0; |
80 | 79 |
81 } | 80 } |
82 | 81 |
83 /* Send a banner message if specified to the client. The client might | 82 /* Send a banner message if specified to the client. The client might |
84 * ignore this, but possibly serves as a legal "no trespassing" sign */ | 83 * ignore this, but possibly serves as a legal "no trespassing" sign */ |
85 static void send_msg_userauth_banner() { | 84 void send_msg_userauth_banner(buffer *banner) { |
86 | 85 |
87 TRACE(("enter send_msg_userauth_banner")) | 86 TRACE(("enter send_msg_userauth_banner")) |
88 if (svr_opts.banner == NULL) { | |
89 TRACE(("leave send_msg_userauth_banner: banner is NULL")) | |
90 return; | |
91 } | |
92 | 87 |
93 CHECKCLEARTOWRITE(); | 88 CHECKCLEARTOWRITE(); |
94 | 89 |
95 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER); | 90 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER); |
96 buf_putbufstring(ses.writepayload, svr_opts.banner); | 91 buf_putbufstring(ses.writepayload, banner); |
97 buf_putstring(ses.writepayload, "en", 2); | 92 buf_putstring(ses.writepayload, "en", 2); |
98 | 93 |
99 encrypt_packet(); | 94 encrypt_packet(); |
100 buf_free(svr_opts.banner); | |
101 svr_opts.banner = NULL; | |
102 | 95 |
103 TRACE(("leave send_msg_userauth_banner")) | 96 TRACE(("leave send_msg_userauth_banner")) |
104 } | 97 } |
105 | 98 |
106 /* handle a userauth request, check validity, pass to password or pubkey | 99 /* handle a userauth request, check validity, pass to password or pubkey |
107 * checking, and handle success or failure */ | 100 * checking, and handle success or failure */ |
108 void recv_msg_userauth_request() { | 101 void recv_msg_userauth_request() { |
109 | 102 |
110 unsigned char *username = NULL, *servicename = NULL, *methodname = NULL; | 103 unsigned char *username = NULL, *servicename = NULL, *methodname = NULL; |
111 unsigned int userlen, servicelen, methodlen; | 104 unsigned int userlen, servicelen, methodlen; |
105 int valid_user = 0; | |
112 | 106 |
113 TRACE(("enter recv_msg_userauth_request")) | 107 TRACE(("enter recv_msg_userauth_request")) |
114 | 108 |
115 /* ignore packets if auth is already done */ | 109 /* ignore packets if auth is already done */ |
116 if (ses.authstate.authdone == 1) { | 110 if (ses.authstate.authdone == 1) { |
118 return; | 112 return; |
119 } | 113 } |
120 | 114 |
121 /* send the banner if it exists, it will only exist once */ | 115 /* send the banner if it exists, it will only exist once */ |
122 if (svr_opts.banner) { | 116 if (svr_opts.banner) { |
123 send_msg_userauth_banner(); | 117 send_msg_userauth_banner(svr_opts.banner); |
124 } | 118 buf_free(svr_opts.banner); |
125 | 119 svr_opts.banner = NULL; |
126 | 120 } |
121 | |
127 username = buf_getstring(ses.payload, &userlen); | 122 username = buf_getstring(ses.payload, &userlen); |
128 servicename = buf_getstring(ses.payload, &servicelen); | 123 servicename = buf_getstring(ses.payload, &servicelen); |
129 methodname = buf_getstring(ses.payload, &methodlen); | 124 methodname = buf_getstring(ses.payload, &methodlen); |
130 | 125 |
131 /* only handle 'ssh-connection' currently */ | 126 /* only handle 'ssh-connection' currently */ |
138 m_free(servicename); | 133 m_free(servicename); |
139 m_free(methodname); | 134 m_free(methodname); |
140 dropbear_exit("unknown service in auth"); | 135 dropbear_exit("unknown service in auth"); |
141 } | 136 } |
142 | 137 |
143 /* check username is good before continuing */ | 138 /* check username is good before continuing. |
144 if (checkusername(username, userlen) == DROPBEAR_FAILURE) { | 139 * the 'incrfail' varies depending on the auth method to |
145 /* username is invalid/no shell/etc - send failure */ | 140 * avoid giving away which users exist on the system through |
146 TRACE(("sending checkusername failure")) | 141 * the time delay. */ |
147 send_msg_userauth_failure(0, 1); | 142 if (checkusername(username, userlen) == DROPBEAR_SUCCESS) { |
148 goto out; | 143 valid_user = 1; |
149 } | 144 } |
150 | 145 |
151 /* user wants to know what methods are supported */ | 146 /* user wants to know what methods are supported */ |
152 if (methodlen == AUTH_METHOD_NONE_LEN && | 147 if (methodlen == AUTH_METHOD_NONE_LEN && |
153 strncmp(methodname, AUTH_METHOD_NONE, | 148 strncmp(methodname, AUTH_METHOD_NONE, |
154 AUTH_METHOD_NONE_LEN) == 0) { | 149 AUTH_METHOD_NONE_LEN) == 0) { |
155 TRACE(("recv_msg_userauth_request: 'none' request")) | 150 TRACE(("recv_msg_userauth_request: 'none' request")) |
156 if (svr_opts.allowblankpass | 151 if (valid_user |
152 && svr_opts.allowblankpass | |
157 && !svr_opts.noauthpass | 153 && !svr_opts.noauthpass |
158 && !(svr_opts.norootpass && ses.authstate.pw_uid == 0) | 154 && !(svr_opts.norootpass && ses.authstate.pw_uid == 0) |
159 && ses.authstate.pw_passwd[0] == '\0') | 155 && ses.authstate.pw_passwd[0] == '\0') |
160 { | 156 { |
161 dropbear_log(LOG_NOTICE, | 157 dropbear_log(LOG_NOTICE, |
165 send_msg_userauth_success(); | 161 send_msg_userauth_success(); |
166 goto out; | 162 goto out; |
167 } | 163 } |
168 else | 164 else |
169 { | 165 { |
166 /* 'none' has no failure delay */ | |
170 send_msg_userauth_failure(0, 0); | 167 send_msg_userauth_failure(0, 0); |
171 goto out; | 168 goto out; |
172 } | 169 } |
173 } | 170 } |
174 | 171 |
177 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { | 174 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { |
178 /* user wants to try password auth */ | 175 /* user wants to try password auth */ |
179 if (methodlen == AUTH_METHOD_PASSWORD_LEN && | 176 if (methodlen == AUTH_METHOD_PASSWORD_LEN && |
180 strncmp(methodname, AUTH_METHOD_PASSWORD, | 177 strncmp(methodname, AUTH_METHOD_PASSWORD, |
181 AUTH_METHOD_PASSWORD_LEN) == 0) { | 178 AUTH_METHOD_PASSWORD_LEN) == 0) { |
182 svr_auth_password(); | 179 if (valid_user) { |
183 goto out; | 180 svr_auth_password(); |
181 goto out; | |
182 } | |
184 } | 183 } |
185 } | 184 } |
186 #endif | 185 #endif |
187 | 186 |
188 #ifdef ENABLE_SVR_PAM_AUTH | 187 #ifdef ENABLE_SVR_PAM_AUTH |
190 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { | 189 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { |
191 /* user wants to try password auth */ | 190 /* user wants to try password auth */ |
192 if (methodlen == AUTH_METHOD_PASSWORD_LEN && | 191 if (methodlen == AUTH_METHOD_PASSWORD_LEN && |
193 strncmp(methodname, AUTH_METHOD_PASSWORD, | 192 strncmp(methodname, AUTH_METHOD_PASSWORD, |
194 AUTH_METHOD_PASSWORD_LEN) == 0) { | 193 AUTH_METHOD_PASSWORD_LEN) == 0) { |
195 svr_auth_pam(); | 194 if (valid_user) { |
196 goto out; | 195 svr_auth_pam(); |
196 goto out; | |
197 } | |
197 } | 198 } |
198 } | 199 } |
199 #endif | 200 #endif |
200 | 201 |
201 #ifdef ENABLE_SVR_PUBKEY_AUTH | 202 #ifdef ENABLE_SVR_PUBKEY_AUTH |
202 /* user wants to try pubkey auth */ | 203 /* user wants to try pubkey auth */ |
203 if (methodlen == AUTH_METHOD_PUBKEY_LEN && | 204 if (methodlen == AUTH_METHOD_PUBKEY_LEN && |
204 strncmp(methodname, AUTH_METHOD_PUBKEY, | 205 strncmp(methodname, AUTH_METHOD_PUBKEY, |
205 AUTH_METHOD_PUBKEY_LEN) == 0) { | 206 AUTH_METHOD_PUBKEY_LEN) == 0) { |
206 svr_auth_pubkey(); | 207 if (valid_user) { |
208 svr_auth_pubkey(); | |
209 } else { | |
210 /* pubkey has no failure delay */ | |
211 send_msg_userauth_failure(0, 0); | |
212 } | |
207 goto out; | 213 goto out; |
208 } | 214 } |
209 #endif | 215 #endif |
210 | 216 |
211 /* nothing matched, we just fail */ | 217 /* nothing matched, we just fail with a delay */ |
212 send_msg_userauth_failure(0, 1); | 218 send_msg_userauth_failure(0, 1); |
213 | 219 |
214 out: | 220 out: |
215 | 221 |
216 m_free(username); | 222 m_free(username); |
249 if (!ses.authstate.pw_name) { | 255 if (!ses.authstate.pw_name) { |
250 TRACE(("leave checkusername: user '%s' doesn't exist", username)) | 256 TRACE(("leave checkusername: user '%s' doesn't exist", username)) |
251 dropbear_log(LOG_WARNING, | 257 dropbear_log(LOG_WARNING, |
252 "Login attempt for nonexistent user from %s", | 258 "Login attempt for nonexistent user from %s", |
253 svr_ses.addrstring); | 259 svr_ses.addrstring); |
254 send_msg_userauth_failure(0, 1); | |
255 return DROPBEAR_FAILURE; | 260 return DROPBEAR_FAILURE; |
256 } | 261 } |
257 | 262 |
258 /* check if we are running as non-root, and login user is different from the server */ | 263 /* check if we are running as non-root, and login user is different from the server */ |
259 uid = geteuid(); | 264 uid = geteuid(); |
261 TRACE(("running as nonroot, only server uid is allowed")) | 266 TRACE(("running as nonroot, only server uid is allowed")) |
262 dropbear_log(LOG_WARNING, | 267 dropbear_log(LOG_WARNING, |
263 "Login attempt with wrong user %s from %s", | 268 "Login attempt with wrong user %s from %s", |
264 ses.authstate.pw_name, | 269 ses.authstate.pw_name, |
265 svr_ses.addrstring); | 270 svr_ses.addrstring); |
266 send_msg_userauth_failure(0, 1); | |
267 return DROPBEAR_FAILURE; | 271 return DROPBEAR_FAILURE; |
268 } | 272 } |
269 | 273 |
270 /* check for non-root if desired */ | 274 /* check for non-root if desired */ |
271 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { | 275 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { |
272 TRACE(("leave checkusername: root login disabled")) | 276 TRACE(("leave checkusername: root login disabled")) |
273 dropbear_log(LOG_WARNING, "root login rejected"); | 277 dropbear_log(LOG_WARNING, "root login rejected"); |
274 send_msg_userauth_failure(0, 1); | |
275 return DROPBEAR_FAILURE; | 278 return DROPBEAR_FAILURE; |
276 } | 279 } |
277 | 280 |
278 TRACE(("shell is %s", ses.authstate.pw_shell)) | 281 TRACE(("shell is %s", ses.authstate.pw_shell)) |
279 | 282 |
298 /* no matching shell */ | 301 /* no matching shell */ |
299 endusershell(); | 302 endusershell(); |
300 TRACE(("no matching shell")) | 303 TRACE(("no matching shell")) |
301 dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", | 304 dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", |
302 ses.authstate.pw_name); | 305 ses.authstate.pw_name); |
303 send_msg_userauth_failure(0, 1); | |
304 return DROPBEAR_FAILURE; | 306 return DROPBEAR_FAILURE; |
305 | 307 |
306 goodshell: | 308 goodshell: |
307 endusershell(); | 309 endusershell(); |
308 TRACE(("matching shell")) | 310 TRACE(("matching shell")) |
309 | 311 |
310 TRACE(("uid = %d", ses.authstate.pw_uid)) | 312 TRACE(("uid = %d", ses.authstate.pw_uid)) |
311 TRACE(("leave checkusername")) | 313 TRACE(("leave checkusername")) |
312 return DROPBEAR_SUCCESS; | 314 return DROPBEAR_SUCCESS; |
313 | |
314 } | 315 } |
315 | 316 |
316 /* Send a failure message to the client, in responds to a userauth_request. | 317 /* Send a failure message to the client, in responds to a userauth_request. |
317 * Partial indicates whether to set the "partial success" flag, | 318 * Partial indicates whether to set the "partial success" flag, |
318 * incrfail is whether to count this failure in the failure count (which | 319 * incrfail is whether to count this failure in the failure count (which |
353 encrypt_packet(); | 354 encrypt_packet(); |
354 | 355 |
355 if (incrfail) { | 356 if (incrfail) { |
356 unsigned int delay; | 357 unsigned int delay; |
357 genrandom((unsigned char*)&delay, sizeof(delay)); | 358 genrandom((unsigned char*)&delay, sizeof(delay)); |
358 /* We delay for 300ms +- 50ms, 0.1ms granularity */ | 359 /* We delay for 300ms +- 50ms */ |
359 delay = 250000 + (delay % 1000)*100; | 360 delay = 250000 + (delay % 100000); |
360 usleep(delay); | 361 usleep(delay); |
361 ses.authstate.failcount++; | 362 ses.authstate.failcount++; |
362 } | 363 } |
363 | 364 |
364 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { | 365 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { |