Mercurial > dropbear
comparison svr-auth.c @ 464:4317be8b7cf9
Make a copy of passwd fields since getpwnam()'s retval isn't safe to keep
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 13 Jan 2008 03:55:59 +0000 |
parents | 7e43f5e473b9 |
children | f33b0898aaa6 |
comparison
equal
deleted
inserted
replaced
461:db4f6adcb7e2 | 464:4317be8b7cf9 |
---|---|
40 | 40 |
41 /* initialise the first time for a session, resetting all parameters */ | 41 /* initialise the first time for a session, resetting all parameters */ |
42 void svr_authinitialise() { | 42 void svr_authinitialise() { |
43 | 43 |
44 ses.authstate.failcount = 0; | 44 ses.authstate.failcount = 0; |
45 ses.authstate.pw_name = NULL; | |
46 ses.authstate.pw_dir = NULL; | |
47 ses.authstate.pw_shell = NULL; | |
48 ses.authstate.pw_passwd = NULL; | |
45 authclear(); | 49 authclear(); |
46 | 50 |
47 } | 51 } |
48 | 52 |
49 /* Reset the auth state, but don't reset the failcount. This is for if the | 53 /* Reset the auth state, but don't reset the failcount. This is for if the |
58 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) | 62 #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) |
59 if (!svr_opts.noauthpass) { | 63 if (!svr_opts.noauthpass) { |
60 ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; | 64 ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; |
61 } | 65 } |
62 #endif | 66 #endif |
63 | 67 if (ses.authstate.pw_name) { |
68 m_free(ses.authstate.pw_name); | |
69 } | |
70 if (ses.authstate.pw_shell) { | |
71 m_free(ses.authstate.pw_shell); | |
72 } | |
73 if (ses.authstate.pw_dir) { | |
74 m_free(ses.authstate.pw_dir); | |
75 } | |
76 if (ses.authstate.pw_passwd) { | |
77 m_free(ses.authstate.pw_passwd); | |
78 } | |
79 | |
64 } | 80 } |
65 | 81 |
66 /* 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 |
67 * ignore this, but possibly serves as a legal "no trespassing" sign */ | 83 * ignore this, but possibly serves as a legal "no trespassing" sign */ |
68 static void send_msg_userauth_banner() { | 84 static void send_msg_userauth_banner() { |
141 goto out; | 157 goto out; |
142 } | 158 } |
143 | 159 |
144 #ifdef ENABLE_SVR_PASSWORD_AUTH | 160 #ifdef ENABLE_SVR_PASSWORD_AUTH |
145 if (!svr_opts.noauthpass && | 161 if (!svr_opts.noauthpass && |
146 !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { | 162 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { |
147 /* user wants to try password auth */ | 163 /* user wants to try password auth */ |
148 if (methodlen == AUTH_METHOD_PASSWORD_LEN && | 164 if (methodlen == AUTH_METHOD_PASSWORD_LEN && |
149 strncmp(methodname, AUTH_METHOD_PASSWORD, | 165 strncmp(methodname, AUTH_METHOD_PASSWORD, |
150 AUTH_METHOD_PASSWORD_LEN) == 0) { | 166 AUTH_METHOD_PASSWORD_LEN) == 0) { |
151 svr_auth_password(); | 167 svr_auth_password(); |
154 } | 170 } |
155 #endif | 171 #endif |
156 | 172 |
157 #ifdef ENABLE_SVR_PAM_AUTH | 173 #ifdef ENABLE_SVR_PAM_AUTH |
158 if (!svr_opts.noauthpass && | 174 if (!svr_opts.noauthpass && |
159 !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { | 175 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { |
160 /* user wants to try password auth */ | 176 /* user wants to try password auth */ |
161 if (methodlen == AUTH_METHOD_PASSWORD_LEN && | 177 if (methodlen == AUTH_METHOD_PASSWORD_LEN && |
162 strncmp(methodname, AUTH_METHOD_PASSWORD, | 178 strncmp(methodname, AUTH_METHOD_PASSWORD, |
163 AUTH_METHOD_PASSWORD_LEN) == 0) { | 179 AUTH_METHOD_PASSWORD_LEN) == 0) { |
164 svr_auth_pam(); | 180 svr_auth_pam(); |
185 m_free(username); | 201 m_free(username); |
186 m_free(servicename); | 202 m_free(servicename); |
187 m_free(methodname); | 203 m_free(methodname); |
188 } | 204 } |
189 | 205 |
206 static int fill_passwd(const char* username) { | |
207 struct passwd *pw = NULL; | |
208 if (ses.authstate.pw_name) | |
209 m_free(ses.authstate.pw_name); | |
210 if (ses.authstate.pw_dir) | |
211 m_free(ses.authstate.pw_dir); | |
212 if (ses.authstate.pw_shell) | |
213 m_free(ses.authstate.pw_shell); | |
214 if (ses.authstate.pw_passwd) | |
215 m_free(ses.authstate.pw_passwd); | |
216 | |
217 pw = getpwnam(username); | |
218 if (!pw) { | |
219 return; | |
220 } | |
221 ses.authstate.pw_uid = pw->pw_uid; | |
222 ses.authstate.pw_gid = pw->pw_gid; | |
223 ses.authstate.pw_name = m_strdup(pw->pw_name); | |
224 ses.authstate.pw_dir = m_strdup(pw->pw_dir); | |
225 ses.authstate.pw_shell = m_strdup(pw->pw_shell); | |
226 ses.authstate.pw_passwd = m_strdup(pw->pw_passwd); | |
227 } | |
228 | |
229 | |
190 /* Check that the username exists, has a non-empty password, and has a valid | 230 /* Check that the username exists, has a non-empty password, and has a valid |
191 * shell. | 231 * shell. |
192 * returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */ | 232 * returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */ |
193 static int checkusername(unsigned char *username, unsigned int userlen) { | 233 static int checkusername(unsigned char *username, unsigned int userlen) { |
194 | 234 |
195 char* listshell = NULL; | 235 char* listshell = NULL; |
196 char* usershell = NULL; | 236 char* usershell = NULL; |
197 | |
198 TRACE(("enter checkusername")) | 237 TRACE(("enter checkusername")) |
199 if (userlen > MAX_USERNAME_LEN) { | 238 if (userlen > MAX_USERNAME_LEN) { |
200 return DROPBEAR_FAILURE; | 239 return DROPBEAR_FAILURE; |
201 } | 240 } |
202 | 241 |
208 dropbear_log(LOG_WARNING, "client trying multiple usernames from %s", | 247 dropbear_log(LOG_WARNING, "client trying multiple usernames from %s", |
209 svr_ses.addrstring); | 248 svr_ses.addrstring); |
210 m_free(ses.authstate.username); | 249 m_free(ses.authstate.username); |
211 } | 250 } |
212 authclear(); | 251 authclear(); |
213 ses.authstate.pw = getpwnam((char*)username); | 252 fill_passwd(username); |
214 ses.authstate.username = m_strdup(username); | 253 ses.authstate.username = m_strdup(username); |
215 m_free(ses.authstate.printableuser); | |
216 } | 254 } |
217 | 255 |
218 /* check that user exists */ | 256 /* check that user exists */ |
219 if (ses.authstate.pw == NULL) { | 257 if (!ses.authstate.pw_name) { |
220 TRACE(("leave checkusername: user '%s' doesn't exist", username)) | 258 TRACE(("leave checkusername: user '%s' doesn't exist", username)) |
221 dropbear_log(LOG_WARNING, | 259 dropbear_log(LOG_WARNING, |
222 "login attempt for nonexistent user from %s", | 260 "login attempt for nonexistent user from %s", |
223 svr_ses.addrstring); | 261 svr_ses.addrstring); |
224 send_msg_userauth_failure(0, 1); | 262 send_msg_userauth_failure(0, 1); |
225 return DROPBEAR_FAILURE; | 263 return DROPBEAR_FAILURE; |
226 } | 264 } |
227 | 265 |
228 /* We can set it once we know its a real user */ | |
229 ses.authstate.printableuser = m_strdup(ses.authstate.pw->pw_name); | |
230 | |
231 /* check for non-root if desired */ | 266 /* check for non-root if desired */ |
232 if (svr_opts.norootlogin && ses.authstate.pw->pw_uid == 0) { | 267 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { |
233 TRACE(("leave checkusername: root login disabled")) | 268 TRACE(("leave checkusername: root login disabled")) |
234 dropbear_log(LOG_WARNING, "root login rejected"); | 269 dropbear_log(LOG_WARNING, "root login rejected"); |
235 send_msg_userauth_failure(0, 1); | 270 send_msg_userauth_failure(0, 1); |
236 return DROPBEAR_FAILURE; | 271 return DROPBEAR_FAILURE; |
237 } | 272 } |
238 | 273 |
239 /* check for an empty password */ | 274 /* check for an empty password */ |
240 if (ses.authstate.pw->pw_passwd[0] == '\0') { | 275 if (ses.authstate.pw_passwd[0] == '\0') { |
241 TRACE(("leave checkusername: empty pword")) | 276 TRACE(("leave checkusername: empty pword")) |
242 dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected", | 277 dropbear_log(LOG_WARNING, "user '%s' has blank password, rejected", |
243 ses.authstate.printableuser); | 278 ses.authstate.pw_name); |
244 send_msg_userauth_failure(0, 1); | 279 send_msg_userauth_failure(0, 1); |
245 return DROPBEAR_FAILURE; | 280 return DROPBEAR_FAILURE; |
246 } | 281 } |
247 | 282 |
248 TRACE(("shell is %s", ses.authstate.pw->pw_shell)) | 283 TRACE(("shell is %s", ses.authstate.pw_shell)) |
249 | 284 |
250 /* check that the shell is set */ | 285 /* check that the shell is set */ |
251 usershell = ses.authstate.pw->pw_shell; | 286 usershell = ses.authstate.pw_shell; |
252 if (usershell[0] == '\0') { | 287 if (usershell[0] == '\0') { |
253 /* empty shell in /etc/passwd means /bin/sh according to passwd(5) */ | 288 /* empty shell in /etc/passwd means /bin/sh according to passwd(5) */ |
254 usershell = "/bin/sh"; | 289 usershell = "/bin/sh"; |
255 } | 290 } |
256 | 291 |
267 } | 302 } |
268 /* no matching shell */ | 303 /* no matching shell */ |
269 endusershell(); | 304 endusershell(); |
270 TRACE(("no matching shell")) | 305 TRACE(("no matching shell")) |
271 dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected", | 306 dropbear_log(LOG_WARNING, "user '%s' has invalid shell, rejected", |
272 ses.authstate.printableuser); | 307 ses.authstate.pw_name); |
273 send_msg_userauth_failure(0, 1); | 308 send_msg_userauth_failure(0, 1); |
274 return DROPBEAR_FAILURE; | 309 return DROPBEAR_FAILURE; |
275 | 310 |
276 goodshell: | 311 goodshell: |
277 endusershell(); | 312 endusershell(); |
278 TRACE(("matching shell")) | 313 TRACE(("matching shell")) |
279 | 314 |
280 TRACE(("uid = %d", ses.authstate.pw->pw_uid)) | 315 TRACE(("uid = %d", ses.authstate.pw_uid)) |
281 TRACE(("leave checkusername")) | 316 TRACE(("leave checkusername")) |
282 return DROPBEAR_SUCCESS; | 317 return DROPBEAR_SUCCESS; |
283 | 318 |
284 } | 319 } |
285 | 320 |
332 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { | 367 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { |
333 char * userstr; | 368 char * userstr; |
334 /* XXX - send disconnect ? */ | 369 /* XXX - send disconnect ? */ |
335 TRACE(("Max auth tries reached, exiting")) | 370 TRACE(("Max auth tries reached, exiting")) |
336 | 371 |
337 if (ses.authstate.printableuser == NULL) { | 372 if (ses.authstate.pw_name == NULL) { |
338 userstr = "is invalid"; | 373 userstr = "is invalid"; |
339 } else { | 374 } else { |
340 userstr = ses.authstate.printableuser; | 375 userstr = ses.authstate.pw_name; |
341 } | 376 } |
342 dropbear_exit("Max auth tries reached - user '%s' from %s", | 377 dropbear_exit("Max auth tries reached - user '%s' from %s", |
343 userstr, svr_ses.addrstring); | 378 userstr, svr_ses.addrstring); |
344 } | 379 } |
345 | 380 |
358 | 393 |
359 ses.authstate.authdone = 1; | 394 ses.authstate.authdone = 1; |
360 ses.connect_time = 0; | 395 ses.connect_time = 0; |
361 | 396 |
362 | 397 |
363 if (ses.authstate.pw->pw_uid == 0) { | 398 if (ses.authstate.pw_uid == 0) { |
364 ses.allowprivport = 1; | 399 ses.allowprivport = 1; |
365 } | 400 } |
366 | 401 |
367 /* Remove from the list of pre-auth sockets. Should be m_close(), since if | 402 /* Remove from the list of pre-auth sockets. Should be m_close(), since if |
368 * we fail, we might end up leaking connection slots, and disallow new | 403 * we fail, we might end up leaking connection slots, and disallow new |