comparison svr-auth.c @ 1546:bb8eaa26bc93 fuzz

merge from main
author Matt Johnston <matt@ucc.asn.au>
date Mon, 26 Feb 2018 22:44:48 +0800
parents 5916af64acd4 51df3d53b050
children 61a793b6e471
comparison
equal deleted inserted replaced
1530:63fa53d3b6c7 1546:bb8eaa26bc93
23 * SOFTWARE. */ 23 * SOFTWARE. */
24 24
25 /* This file (auth.c) handles authentication requests, passing it to the 25 /* This file (auth.c) handles authentication requests, passing it to the
26 * particular type (auth-passwd, auth-pubkey). */ 26 * particular type (auth-passwd, auth-pubkey). */
27 27
28 #include <limits.h>
29
28 #include "includes.h" 30 #include "includes.h"
29 #include "dbutil.h" 31 #include "dbutil.h"
30 #include "session.h" 32 #include "session.h"
31 #include "buffer.h" 33 #include "buffer.h"
32 #include "ssh.h" 34 #include "ssh.h"
33 #include "packet.h" 35 #include "packet.h"
34 #include "auth.h" 36 #include "auth.h"
35 #include "runopts.h" 37 #include "runopts.h"
36 #include "dbrandom.h" 38 #include "dbrandom.h"
37 39
38 static void authclear(void); 40 static int checkusername(const char *username, unsigned int userlen);
39 static int checkusername(char *username, unsigned int userlen);
40 41
41 /* initialise the first time for a session, resetting all parameters */ 42 /* initialise the first time for a session, resetting all parameters */
42 void svr_authinitialise() { 43 void svr_authinitialise() {
43
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;
49 authclear();
50
51 }
52
53 /* Reset the auth state, but don't reset the failcount. This is for if the
54 * user decides to try with a different username etc, and is also invoked
55 * on initialisation */
56 static void authclear() {
57
58 memset(&ses.authstate, 0, sizeof(ses.authstate)); 44 memset(&ses.authstate, 0, sizeof(ses.authstate));
59 #if DROPBEAR_SVR_PUBKEY_AUTH 45 #if DROPBEAR_SVR_PUBKEY_AUTH
60 ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; 46 ses.authstate.authtypes |= AUTH_TYPE_PUBKEY;
61 #endif 47 #endif
62 #if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH 48 #if DROPBEAR_SVR_PASSWORD_AUTH || DROPBEAR_SVR_PAM_AUTH
63 if (!svr_opts.noauthpass) { 49 if (!svr_opts.noauthpass) {
64 ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; 50 ses.authstate.authtypes |= AUTH_TYPE_PASSWORD;
65 } 51 }
66 #endif 52 #endif
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
80 } 53 }
81 54
82 /* Send a banner message if specified to the client. The client might 55 /* Send a banner message if specified to the client. The client might
83 * ignore this, but possibly serves as a legal "no trespassing" sign */ 56 * ignore this, but possibly serves as a legal "no trespassing" sign */
84 void send_msg_userauth_banner(const buffer *banner) { 57 void send_msg_userauth_banner(const buffer *banner) {
222 m_free(username); 195 m_free(username);
223 m_free(servicename); 196 m_free(servicename);
224 m_free(methodname); 197 m_free(methodname);
225 } 198 }
226 199
200 /* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
201 static int check_group_membership(gid_t check_gid, const char* username, gid_t user_gid) {
202 int ngroups, i, ret;
203 gid_t *grouplist = NULL;
204 int match = DROPBEAR_FAILURE;
205
206 for (ngroups = 32; ngroups <= DROPBEAR_NGROUP_MAX; ngroups *= 2) {
207 grouplist = m_malloc(sizeof(gid_t) * ngroups);
208
209 /* BSD returns ret==0 on success. Linux returns ret==ngroups on success */
210 ret = getgrouplist(username, user_gid, grouplist, &ngroups);
211 if (ret >= 0) {
212 break;
213 }
214 m_free(grouplist);
215 grouplist = NULL;
216 }
217
218 if (!grouplist) {
219 dropbear_log(LOG_ERR, "Too many groups for user '%s'", username);
220 return DROPBEAR_FAILURE;
221 }
222
223 for (i = 0; i < ngroups; i++) {
224 if (grouplist[i] == check_gid) {
225 match = DROPBEAR_SUCCESS;
226 break;
227 }
228 }
229 m_free(grouplist);
230
231 return match;
232 }
233
227 234
228 /* Check that the username exists and isn't disallowed (root), and has a valid shell. 235 /* Check that the username exists and isn't disallowed (root), and has a valid shell.
229 * returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */ 236 * returns DROPBEAR_SUCCESS on valid username, DROPBEAR_FAILURE on failure */
230 static int checkusername(char *username, unsigned int userlen) { 237 static int checkusername(const char *username, unsigned int userlen) {
231 238
232 char* listshell = NULL; 239 char* listshell = NULL;
233 char* usershell = NULL; 240 char* usershell = NULL;
234 uid_t uid; 241 uid_t uid;
242
235 TRACE(("enter checkusername")) 243 TRACE(("enter checkusername"))
236 if (userlen > MAX_USERNAME_LEN) { 244 if (userlen > MAX_USERNAME_LEN) {
237 return DROPBEAR_FAILURE; 245 return DROPBEAR_FAILURE;
238 } 246 }
239 247
240 /* new user or username has changed */ 248 if (strlen(username) != userlen) {
241 if (ses.authstate.username == NULL || 249 dropbear_exit("Attempted username with a null byte from %s",
242 strcmp(username, ses.authstate.username) != 0) { 250 svr_ses.addrstring);
243 /* the username needs resetting */ 251 }
244 if (ses.authstate.username != NULL) { 252
245 dropbear_log(LOG_WARNING, "Client trying multiple usernames from %s", 253 if (ses.authstate.username == NULL) {
246 svr_ses.addrstring); 254 /* first request */
247 m_free(ses.authstate.username); 255 fill_passwd(username);
248 } 256 ses.authstate.username = m_strdup(username);
249 authclear(); 257 } else {
250 fill_passwd(username); 258 /* check username hasn't changed */
251 ses.authstate.username = m_strdup(username); 259 if (strcmp(username, ses.authstate.username) != 0) {
260 dropbear_exit("Client trying multiple usernames from %s",
261 svr_ses.addrstring);
262 }
263 }
264
265 /* avoids cluttering logs with repeated failure messages from
266 consecutive authentication requests in a sesssion */
267 if (ses.authstate.checkusername_failed) {
268 TRACE(("checkusername: returning cached failure"))
269 return DROPBEAR_FAILURE;
252 } 270 }
253 271
254 /* check that user exists */ 272 /* check that user exists */
255 if (!ses.authstate.pw_name) { 273 if (!ses.authstate.pw_name) {
256 TRACE(("leave checkusername: user '%s' doesn't exist", username)) 274 TRACE(("leave checkusername: user '%s' doesn't exist", username))
257 dropbear_log(LOG_WARNING, 275 dropbear_log(LOG_WARNING,
258 "Login attempt for nonexistent user from %s", 276 "Login attempt for nonexistent user from %s",
259 svr_ses.addrstring); 277 svr_ses.addrstring);
278 ses.authstate.checkusername_failed = 1;
260 return DROPBEAR_FAILURE; 279 return DROPBEAR_FAILURE;
261 } 280 }
262 281
263 /* check if we are running as non-root, and login user is different from the server */ 282 /* check if we are running as non-root, and login user is different from the server */
264 uid = geteuid(); 283 uid = geteuid();
266 TRACE(("running as nonroot, only server uid is allowed")) 285 TRACE(("running as nonroot, only server uid is allowed"))
267 dropbear_log(LOG_WARNING, 286 dropbear_log(LOG_WARNING,
268 "Login attempt with wrong user %s from %s", 287 "Login attempt with wrong user %s from %s",
269 ses.authstate.pw_name, 288 ses.authstate.pw_name,
270 svr_ses.addrstring); 289 svr_ses.addrstring);
290 ses.authstate.checkusername_failed = 1;
271 return DROPBEAR_FAILURE; 291 return DROPBEAR_FAILURE;
272 } 292 }
273 293
274 /* check for non-root if desired */ 294 /* check for non-root if desired */
275 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { 295 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) {
276 TRACE(("leave checkusername: root login disabled")) 296 TRACE(("leave checkusername: root login disabled"))
277 dropbear_log(LOG_WARNING, "root login rejected"); 297 dropbear_log(LOG_WARNING, "root login rejected");
278 return DROPBEAR_FAILURE; 298 ses.authstate.checkusername_failed = 1;
299 return DROPBEAR_FAILURE;
300 }
301
302 /* check for login restricted to certain group if desired */
303 if (svr_opts.restrict_group) {
304 if (check_group_membership(svr_opts.restrict_group_gid,
305 ses.authstate.pw_name, ses.authstate.pw_gid) == DROPBEAR_FAILURE) {
306 dropbear_log(LOG_WARNING,
307 "Logins are restricted to the group %s but user '%s' is not a member",
308 svr_opts.restrict_group, ses.authstate.pw_name);
309 ses.authstate.checkusername_failed = 1;
310 return DROPBEAR_FAILURE;
311 }
279 } 312 }
280 313
281 TRACE(("shell is %s", ses.authstate.pw_shell)) 314 TRACE(("shell is %s", ses.authstate.pw_shell))
282 315
283 /* check that the shell is set */ 316 /* check that the shell is set */
299 } 332 }
300 } 333 }
301 /* no matching shell */ 334 /* no matching shell */
302 endusershell(); 335 endusershell();
303 TRACE(("no matching shell")) 336 TRACE(("no matching shell"))
337 ses.authstate.checkusername_failed = 1;
304 dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", 338 dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected",
305 ses.authstate.pw_name); 339 ses.authstate.pw_name);
306 return DROPBEAR_FAILURE; 340 return DROPBEAR_FAILURE;
307 341
308 goodshell: 342 goodshell: