/* $Id: ssh_v1_auth_server.c,v 1.4 2001/02/11 03:35:18 tls Exp $ */ /* * Copyright 1999 RedBack Networks, Incorporated. * All rights reserved. * * This software is not in the public domain. It is distributed * under the terms of the license in the file LICENSE in the * same directory as this file. If you have received a copy of this * software without the LICENSE file (which means that whoever gave * you this software violated its license) you may obtain a copy from * http://www.panix.com/~tls/LICENSE.txt */ /* * Copyright (c) 2000, 2001 Andrew Brown, Eric Haszlakiewicz, * and Jason Thorpe. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The names of the authors may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "options.h" #include "sshd.h" #include "ssh_buffer.h" #include "ssh_event.h" #include "ssh_v1_messages.h" #include "ssh_v1_proto.h" #include "ssh_util.h" #ifdef WITH_AUTH_RSA #include "ssh_v1_auth_rsa.h" #endif #ifdef WITH_AUTH_PASSWORD #include "ssh_v1_auth_passwd.h" #endif /* * Server routines to get and authenticate the user. */ /* * get_user: Called during the GETUSER state to get the username. * * Assume: buf is discarded after we return. * * Returns: * RET_NEXT_STATE * RET_FAIL * RET_FATAL */ int get_user(ssh_context_t * context, struct ssh_buf * buf, size_t size, int msg_type) { FUNC_DECL(get_user); int ret; struct ssh_event ev; SSH_DLOG(5, ("start\n")); do { /* Only CMSG_USER is valid now. */ if (msg_type != SSH_V1_CMSG_USER) { SSH_DLOG(1, ("get_user: Bogus packet type:%d\n", msg_type)); EVT_V1_DISCONNECT(ev, context, "Packet is not CMSG_USER\n"); ret = RET_FAIL; break; } /* * Save the user-name for later. Don't give any * indication of existance yet. */ context->username = NULL; if (buf_get_binstr(buf, &(context->username), NULL) != 0) { SSH_DLOG(1, ("Unable to get username: %s\n", strerror(errno))); EVT_V1_DISCONNECT(ev, context, "Unable to get username."); ret = RET_FAIL; break; } SSH_DLOG(4, ("Client sent CMSG_USER:%s\n", context->username)); ssh_sys_lookupuser(context, context->username); if (ssh_sys_checkpw(context->username, "") == 0) { /* * User OK w/o password. Send success, tell * sendThread */ ev.event_type = SSH_EVENT_USERAUTH_OK; ev.event_data[0] = SSH_V1_SMSG_SUCCESS; ret = RET_SKIP_STATE; } else { EVT_V1_FAILURE(ev); ret = RET_NEXT_STATE; } } while (0); if (ssh_sys_sendevent(context, &ev) < 0) { if (context->send_pid == -1) SSH_DLOG(1, ("sendThread exited. Exiting recvThread\n")); else SSH_ERROR("Unable to send event"); ssh_exit(context, 1, EXIT_NOW); } SSH_DLOG(5, ("finish\n")); return (ret); } /* * auth_user: implements actual authentication. * * Returns: * RET_NEXT_STATE Successful authentication * RET_OK Not authenticated, but no error * RET_FAIL Authentication failed. * RET_FATAL Fatal error * * Assume: buf is discarded after we return. * * Individual authentication functions follow the following scheme: * RET_OK - No response necessary * RET_FAIL - Send FAILURE message * RET_NEXT_STATE - Send SUCCESS message * RET_FATAL - Send DISCONNECT message with context->disconnect_msg. */ int v1_auth_user(ssh_context_t * context, struct ssh_buf * buf, size_t size, int msg_type) { FUNC_DECL(auth_user); struct ssh_event ev; struct ssh_ev_ua_ok *evua; const char *err_msg; int retval; switch (msg_type) { case SSH_V1_CMSG_AUTH_PASSWORD: #ifdef WITH_AUTH_PASSWORD retval = v1_auth_user_password(context, buf, size); #endif err_msg = "password"; break; case SSH_V1_CMSG_AUTH_RSA: case SSH_V1_CMSG_AUTH_RSA_RESPONSE: #ifdef WITH_AUTH_RSA retval = v1_auth_user_rsa(context, buf, size); #endif err_msg = "RSA"; break; default: SSH_DLOG(3, ("Unknown authentication(%d)\n", msg_type)); err_msg = ""; retval = RET_FAIL; break; } /* If we returned OK, but not authenticated, just return */ if (retval == RET_OK) return (RET_OK); switch (retval) { case RET_NEXT_STATE: SSH_DLOG(4, ("%s authentication succeeded\n", err_msg)); /* Tell sendThread to switch to the user. */ /* and simultaneously tell the other size of the socket */ ev.event_type = SSH_EVENT_USERAUTH_OK; evua = (struct ssh_ev_ua_ok *) ev.event_data; evua->msg_type = SSH_V1_SMSG_SUCCESS; if ((strlen(context->username) + sizeof(*evua)) > SSH_MAX_EVENT_SIZE) { SSH_ERROR("Username too big for event buffer!\n"); ssh_exit(context, 0, EXIT_NOW); } strcpy(evua->username, context->username); break; case RET_FAIL: SSH_DLOG(2, ("%s authentication failed\n", err_msg)); EVT_V1_FAILURE(ev); break; case RET_FATAL: SSH_DLOG(2, ("%s returned fatal error\n", err_msg)); if (context->disconnect_msg == NULL) context->disconnect_msg = "Unknown FATAL error!"; EVT_V1_DISCONNECT(ev, context, context->disconnect_msg); break; default: SSH_ERROR("Invalid authentication return value"); ssh_exit(context, 1, EXIT_NOW); } if (ssh_sys_sendevent(context, &ev) < 0) { if (context->send_pid == -1) SSH_DLOG(1, ("sendThread exited. Exiting recvThread\n")); else SSH_ERROR("Unable to send event"); ssh_exit(context, 1, EXIT_NOW); } return (retval); }