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