/src/dropbear/src/svr-authpasswd.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Dropbear - a SSH2 server |
3 | | * |
4 | | * Copyright (c) 2002,2003 Matt Johnston |
5 | | * All rights reserved. |
6 | | * |
7 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | * of this software and associated documentation files (the "Software"), to deal |
9 | | * in the Software without restriction, including without limitation the rights |
10 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | * copies of the Software, and to permit persons to whom the Software is |
12 | | * furnished to do so, subject to the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be included in |
15 | | * all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | * SOFTWARE. */ |
24 | | |
25 | | /* Validates a user password */ |
26 | | |
27 | | #include "includes.h" |
28 | | #include "session.h" |
29 | | #include "buffer.h" |
30 | | #include "dbutil.h" |
31 | | #include "auth.h" |
32 | | #include "runopts.h" |
33 | | |
34 | | #if DROPBEAR_SVR_PASSWORD_AUTH |
35 | | |
36 | | /* not constant time when strings are differing lengths. |
37 | | string content isn't leaked, and crypt hashes are predictable length. */ |
38 | 0 | static int constant_time_strcmp(const char* a, const char* b) { |
39 | 0 | size_t la = strlen(a); |
40 | 0 | size_t lb = strlen(b); |
41 | |
|
42 | 0 | if (la != lb) { |
43 | 0 | return 1; |
44 | 0 | } |
45 | | |
46 | 0 | return constant_time_memcmp(a, b, la); |
47 | 0 | } |
48 | | |
49 | | /* Process a password auth request, sending success or failure messages as |
50 | | * appropriate */ |
51 | 100 | void svr_auth_password(int valid_user) { |
52 | | |
53 | 100 | char * passwdcrypt = NULL; /* the crypt from /etc/passwd or /etc/shadow */ |
54 | 100 | char * testcrypt = NULL; /* crypt generated from the user's password sent */ |
55 | 100 | char * password = NULL; |
56 | 100 | unsigned int passwordlen; |
57 | 100 | unsigned int changepw; |
58 | | |
59 | | /* check if client wants to change password */ |
60 | 100 | changepw = buf_getbool(ses.payload); |
61 | 100 | if (changepw) { |
62 | | /* not implemented by this server */ |
63 | 51 | send_msg_userauth_failure(0, 1); |
64 | 51 | return; |
65 | 51 | } |
66 | | |
67 | 49 | password = buf_getstring(ses.payload, &passwordlen); |
68 | 49 | if (valid_user && passwordlen <= DROPBEAR_MAX_PASSWORD_LEN) { |
69 | | /* the first bytes of passwdcrypt are the salt */ |
70 | 0 | passwdcrypt = ses.authstate.pw_passwd; |
71 | 0 | testcrypt = crypt(password, passwdcrypt); |
72 | 0 | } |
73 | 49 | m_burn(password, passwordlen); |
74 | 49 | m_free(password); |
75 | | |
76 | | /* After we have got the payload contents we can exit if the username |
77 | | is invalid. Invalid users have already been logged. */ |
78 | 49 | if (!valid_user) { |
79 | 45 | send_msg_userauth_failure(0, 1); |
80 | 45 | return; |
81 | 45 | } |
82 | | |
83 | 4 | if (passwordlen > DROPBEAR_MAX_PASSWORD_LEN) { |
84 | 0 | dropbear_log(LOG_WARNING, |
85 | 0 | "Too-long password attempt for '%s' from %s", |
86 | 0 | ses.authstate.pw_name, |
87 | 0 | svr_ses.addrstring); |
88 | 0 | send_msg_userauth_failure(0, 1); |
89 | 0 | return; |
90 | 0 | } |
91 | | |
92 | 4 | if (testcrypt == NULL) { |
93 | | /* crypt() with an invalid salt like "!!" */ |
94 | 0 | dropbear_log(LOG_WARNING, "User account '%s' is locked", |
95 | 0 | ses.authstate.pw_name); |
96 | 0 | send_msg_userauth_failure(0, 1); |
97 | 0 | return; |
98 | 0 | } |
99 | | |
100 | | /* check for empty password */ |
101 | 4 | if (passwdcrypt[0] == '\0') { |
102 | 0 | dropbear_log(LOG_WARNING, "User '%s' has blank password, rejected", |
103 | 0 | ses.authstate.pw_name); |
104 | 0 | send_msg_userauth_failure(0, 1); |
105 | 0 | return; |
106 | 0 | } |
107 | | |
108 | 4 | if (constant_time_strcmp(testcrypt, passwdcrypt) == 0) { |
109 | 0 | if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PASSWORD)) { |
110 | | /* successful password authentication, but extra auth required */ |
111 | 0 | dropbear_log(LOG_NOTICE, |
112 | 0 | "Password auth succeeded for '%s' from %s, extra auth required", |
113 | 0 | ses.authstate.pw_name, |
114 | 0 | svr_ses.addrstring); |
115 | 0 | ses.authstate.authtypes &= ~AUTH_TYPE_PASSWORD; /* password auth ok, delete the method flag */ |
116 | 0 | send_msg_userauth_failure(1, 0); /* Send partial success */ |
117 | 0 | } else { |
118 | | /* successful authentication */ |
119 | 0 | dropbear_log(LOG_NOTICE, |
120 | 0 | "Password auth succeeded for '%s' from %s", |
121 | 0 | ses.authstate.pw_name, |
122 | 0 | svr_ses.addrstring); |
123 | 0 | send_msg_userauth_success(); |
124 | 0 | } |
125 | 4 | } else { |
126 | 4 | dropbear_log(LOG_WARNING, |
127 | 4 | "Bad password attempt for '%s' from %s", |
128 | 4 | ses.authstate.pw_name, |
129 | 4 | svr_ses.addrstring); |
130 | 4 | send_msg_userauth_failure(0, 1); |
131 | 4 | } |
132 | 4 | } |
133 | | |
134 | | #endif |