comparison svr-auth.c @ 478:d4f32c3443ac dbclient-netcat-alike

propagate from branch 'au.asn.ucc.matt.dropbear' (head f21045c791002d81fc6b8dde6537ea481e513eb2) to branch 'au.asn.ucc.matt.dropbear.dbclient-netcat-alike' (head d1f69334581dc4c35f9ca16aa5355074c9dd315d)
author Matt Johnston <matt@ucc.asn.au>
date Sun, 14 Sep 2008 06:47:51 +0000
parents f33b0898aaa6
children 738313e73b1c
comparison
equal deleted inserted replaced
296:6b41e2cbf071 478:d4f32c3443ac
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 void 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
313 } 348 }
314 349
315 buf_setpos(typebuf, 0); 350 buf_setpos(typebuf, 0);
316 buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len), 351 buf_putstring(ses.writepayload, buf_getptr(typebuf, typebuf->len),
317 typebuf->len); 352 typebuf->len);
353
354 TRACE(("auth fail: methods %d, '%s'", ses.authstate.authtypes,
355 buf_getptr(typebuf, typebuf->len)));
356
318 buf_free(typebuf); 357 buf_free(typebuf);
319 358
320 buf_putbyte(ses.writepayload, partial ? 1 : 0); 359 buf_putbyte(ses.writepayload, partial ? 1 : 0);
321 encrypt_packet(); 360 encrypt_packet();
322
323 TRACE(("auth fail: methods %d, '%s'", ses.authstate.authtypes,
324 buf_getptr(typebuf, typebuf->len)));
325 361
326 if (incrfail) { 362 if (incrfail) {
327 usleep(300000); /* XXX improve this */ 363 usleep(300000); /* XXX improve this */
328 ses.authstate.failcount++; 364 ses.authstate.failcount++;
329 } 365 }
331 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { 367 if (ses.authstate.failcount >= MAX_AUTH_TRIES) {
332 char * userstr; 368 char * userstr;
333 /* XXX - send disconnect ? */ 369 /* XXX - send disconnect ? */
334 TRACE(("Max auth tries reached, exiting")) 370 TRACE(("Max auth tries reached, exiting"))
335 371
336 if (ses.authstate.printableuser == NULL) { 372 if (ses.authstate.pw_name == NULL) {
337 userstr = "is invalid"; 373 userstr = "is invalid";
338 } else { 374 } else {
339 userstr = ses.authstate.printableuser; 375 userstr = ses.authstate.pw_name;
340 } 376 }
341 dropbear_exit("Max auth tries reached - user '%s' from %s", 377 dropbear_exit("Max auth tries reached - user '%s' from %s",
342 userstr, svr_ses.addrstring); 378 userstr, svr_ses.addrstring);
343 } 379 }
344 380
354 390
355 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS); 391 buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_SUCCESS);
356 encrypt_packet(); 392 encrypt_packet();
357 393
358 ses.authstate.authdone = 1; 394 ses.authstate.authdone = 1;
359 ses.connecttimeout = 0; 395 ses.connect_time = 0;
360 396
361 397
362 if (ses.authstate.pw->pw_uid == 0) { 398 if (ses.authstate.pw_uid == 0) {
363 ses.allowprivport = 1; 399 ses.allowprivport = 1;
364 } 400 }
365 401
366 /* 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
367 * 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