1687 lines · 69.8 KB · C
RawDownload
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org> * Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net> * Copyright (c) 2009-2011 by Daniel Stenberg * All rights reserved. * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided * that the following conditions are met: * *   Redistributions of source code must retain the above *   copyright notice, this list of conditions and the *   following disclaimer. * *   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. * *   Neither the name of the copyright holder nor the names *   of any other contributors may be used to endorse or *   promote products derived from this software without *   specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "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 COPYRIGHT OWNER OR * CONTRIBUTORS 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 "libssh2_priv.h" #include <ctype.h>#include <stdio.h> #include <assert.h> /* Needed for struct iovec on some platforms */#ifdef HAVE_SYS_UIO_H#include <sys/uio.h>#endif #include "transport.h"#include "session.h"#include "userauth.h" /* libssh2_userauth_list * * List authentication methods * Will yield successful login if "none" happens to be allowable for this user * Not a common configuration for any SSH server though * username should be NULL, or a null terminated string */static char *userauth_list(LIBSSH2_SESSION *session, const char *username,                           unsigned int username_len){    static const unsigned char reply_codes[3] =        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };    /* packet_type(1) + username_len(4) + service_len(4) +       service(14)"ssh-connection" + method_len(4) = 27 */    unsigned long methods_len;    unsigned char *s;    int rc;     if (session->userauth_list_state == libssh2_NB_state_idle) {        /* Zero the whole thing out */        memset(&session->userauth_list_packet_requirev_state, 0,               sizeof(session->userauth_list_packet_requirev_state));         session->userauth_list_data_len = username_len + 27;         s = session->userauth_list_data =            LIBSSH2_ALLOC(session, session->userauth_list_data_len);        if (!session->userauth_list_data) {            _libssh2_error(session, LIBSSH2_ERROR_ALLOC,                           "Unable to allocate memory for userauth_list");            return NULL;        }         *(s++) = SSH_MSG_USERAUTH_REQUEST;        _libssh2_store_str(&s, username, username_len);        _libssh2_store_str(&s, "ssh-connection", 14);        _libssh2_store_u32(&s, 4); /* send "none" separately */         session->userauth_list_state = libssh2_NB_state_created;    }     if (session->userauth_list_state == libssh2_NB_state_created) {        rc = _libssh2_transport_send(session, session->userauth_list_data,                                     session->userauth_list_data_len,                                     (unsigned char *)"none", 4);        if (rc == LIBSSH2_ERROR_EAGAIN) {            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,                           "Would block requesting userauth list");            return NULL;        }        /* now free the packet that was sent */        LIBSSH2_FREE(session, session->userauth_list_data);        session->userauth_list_data = NULL;         if (rc) {            _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,                           "Unable to send userauth-none request");            session->userauth_list_state = libssh2_NB_state_idle;            return NULL;        }         session->userauth_list_state = libssh2_NB_state_sent;    }     if (session->userauth_list_state == libssh2_NB_state_sent) {        rc = _libssh2_packet_requirev(session, reply_codes,                                      &session->userauth_list_data,                                      &session->userauth_list_data_len, 0,                                      NULL, 0,                                      &session->userauth_list_packet_requirev_state);        if (rc == LIBSSH2_ERROR_EAGAIN) {            _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,                           "Would block requesting userauth list");            return NULL;        } else if (rc) {            _libssh2_error(session, rc, "Failed getting response");            session->userauth_list_state = libssh2_NB_state_idle;            return NULL;        }         if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) {            /* Wow, who'dve thought... */            _libssh2_error(session, LIBSSH2_ERROR_NONE, "No error");            LIBSSH2_FREE(session, session->userauth_list_data);            session->userauth_list_data = NULL;            session->state |= LIBSSH2_STATE_AUTHENTICATED;            session->userauth_list_state = libssh2_NB_state_idle;            return NULL;        }         methods_len = _libssh2_ntohu32(session->userauth_list_data + 1);         /* Do note that the memory areas overlap! */        memmove(session->userauth_list_data, session->userauth_list_data + 5,                methods_len);        session->userauth_list_data[methods_len] = '\0';        _libssh2_debug(session, LIBSSH2_TRACE_AUTH,                       "Permitted auth methods: %s",                       session->userauth_list_data);    }     session->userauth_list_state = libssh2_NB_state_idle;    return (char *) session->userauth_list_data;} /* libssh2_userauth_list * * List authentication methods * Will yield successful login if "none" happens to be allowable for this user * Not a common configuration for any SSH server though * username should be NULL, or a null terminated string */LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user,                      unsigned int user_len){    char *ptr;    BLOCK_ADJUST_ERRNO(ptr, session,                       userauth_list(session, user, user_len));    return ptr;} /* * libssh2_userauth_authenticated * * Returns: 0 if not yet authenticated *          1 if already authenticated */LIBSSH2_API intlibssh2_userauth_authenticated(LIBSSH2_SESSION * session){    return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0;}   /* userauth_password * Plain ol' login */static intuserauth_password(LIBSSH2_SESSION *session,                  const char *username, unsigned int username_len,                  const unsigned char *password, unsigned int password_len,                  LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))){    unsigned char *s;    static const unsigned char reply_codes[4] =        { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,          SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0        };    int rc;     if (session->userauth_pswd_state == libssh2_NB_state_idle) {        /* Zero the whole thing out */        memset(&session->userauth_pswd_packet_requirev_state, 0,               sizeof(session->userauth_pswd_packet_requirev_state));         /*         * 40 = acket_type(1) + username_len(4) + service_len(4) +         * service(14)"ssh-connection" + method_len(4) + method(8)"password" +         * chgpwdbool(1) + password_len(4) */        session->userauth_pswd_data_len = username_len + 40;         session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;         /* TODO: remove this alloc with a fixed buffer in the session           struct */        s = session->userauth_pswd_data =            LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);        if (!session->userauth_pswd_data) {            return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,                                  "Unable to allocate memory for "                                  "userauth-password request");        }         *(s++) = SSH_MSG_USERAUTH_REQUEST;        _libssh2_store_str(&s, username, username_len);        _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1);        _libssh2_store_str(&s, "password", sizeof("password") - 1);        *s++ = '\0';        _libssh2_store_u32(&s, password_len);        /* 'password' is sent separately */         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,                       "Attempting to login using password authentication");         session->userauth_pswd_state = libssh2_NB_state_created;    }     if (session->userauth_pswd_state == libssh2_NB_state_created) {        rc = _libssh2_transport_send(session, session->userauth_pswd_data,                                     session->userauth_pswd_data_len,                                     password, password_len);        if (rc == LIBSSH2_ERROR_EAGAIN) {            return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,                                  "Would block writing password request");        }         /* now free the sent packet */        LIBSSH2_FREE(session, session->userauth_pswd_data);        session->userauth_pswd_data = NULL;         if (rc) {            session->userauth_pswd_state = libssh2_NB_state_idle;            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,                                  "Unable to send userauth-password request");        }         session->userauth_pswd_state = libssh2_NB_state_sent;    }   password_response:     if ((session->userauth_pswd_state == libssh2_NB_state_sent)        || (session->userauth_pswd_state == libssh2_NB_state_sent1)        || (session->userauth_pswd_state == libssh2_NB_state_sent2)) {        if (session->userauth_pswd_state == libssh2_NB_state_sent) {            rc = _libssh2_packet_requirev(session, reply_codes,                                          &session->userauth_pswd_data,                                          &session->userauth_pswd_data_len,                                          0, NULL, 0,                                          &session->                                          userauth_pswd_packet_requirev_state);            if (rc == LIBSSH2_ERROR_EAGAIN) {                return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,                                      "Would block waiting");            } else if (rc) {                session->userauth_pswd_state = libssh2_NB_state_idle;                return _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT,                                      "Would block waiting");            }             if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {                _libssh2_debug(session, LIBSSH2_TRACE_AUTH,                               "Password authentication successful");                LIBSSH2_FREE(session, session->userauth_pswd_data);                session->userauth_pswd_data = NULL;                session->state |= LIBSSH2_STATE_AUTHENTICATED;                session->userauth_pswd_state = libssh2_NB_state_idle;                return 0;            } else if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) {                _libssh2_debug(session, LIBSSH2_TRACE_AUTH,                               "Password authentication failed");                LIBSSH2_FREE(session, session->userauth_pswd_data);                session->userauth_pswd_data = NULL;                session->userauth_pswd_state = libssh2_NB_state_idle;                return _libssh2_error(session,                                      LIBSSH2_ERROR_AUTHENTICATION_FAILED,                                      "Authentication failed "                                      "(username/password)");            }             session->userauth_pswd_newpw = NULL;            session->userauth_pswd_newpw_len = 0;             session->userauth_pswd_state = libssh2_NB_state_sent1;        }         if ((session->userauth_pswd_data[0] ==             SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)            || (session->userauth_pswd_data0 ==                SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) {            session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;             if ((session->userauth_pswd_state == libssh2_NB_state_sent1) ||                (session->userauth_pswd_state == libssh2_NB_state_sent2)) {                if (session->userauth_pswd_state == libssh2_NB_state_sent1) {                    _libssh2_debug(session, LIBSSH2_TRACE_AUTH,                                   "Password change required");                    LIBSSH2_FREE(session, session->userauth_pswd_data);                    session->userauth_pswd_data = NULL;                }                if (passwd_change_cb) {                    if (session->userauth_pswd_state == libssh2_NB_state_sent1) {                        passwd_change_cb(session,                                         &session->userauth_pswd_newpw,                                         &session->userauth_pswd_newpw_len,                                         &session->abstract);                        if (!session->userauth_pswd_newpw) {                            return _libssh2_error(session,                                                  LIBSSH2_ERROR_PASSWORD_EXPIRED,                                                  "Password expired, and "                                                  "callback failed");                        }                         /* basic data_len + newpw_len(4) */                        session->userauth_pswd_data_len =                            username_len + password_len + 44;                         s = session->userauth_pswd_data =                            LIBSSH2_ALLOC(session,                                          session->userauth_pswd_data_len);                        if (!session->userauth_pswd_data) {                            LIBSSH2_FREE(session,                                         session->userauth_pswd_newpw);                            session->userauth_pswd_newpw = NULL;                            return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,                                                  "Unable to allocate memory "                                                  "for userauth password "                                                  "change request");                        }                         *(s++) = SSH_MSG_USERAUTH_REQUEST;                        _libssh2_store_str(&s, username, username_len);                        _libssh2_store_str(&s, "ssh-connection",                                           sizeof("ssh-connection") - 1);                        _libssh2_store_str(&s, "password",                                           sizeof("password") - 1);                        *s++ = 0x01;                        _libssh2_store_str(&s, (char *)password, password_len);                        _libssh2_store_u32(&s,                                           session->userauth_pswd_newpw_len);                        /* send session->userauth_pswd_newpw separately */                         session->userauth_pswd_state = libssh2_NB_state_sent2;                    }                     if (session->userauth_pswd_state == libssh2_NB_state_sent2) {                        rc = _libssh2_transport_send(session,                                                     session->userauth_pswd_data,                                                     session->userauth_pswd_data_len,                                                     (unsigned char *)                                                     session->userauth_pswd_newpw,                                                     session->userauth_pswd_newpw_len);                        if (rc == LIBSSH2_ERROR_EAGAIN) {                            return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,                                                  "Would block waiting");                        }                         /* free the allocated packets again */                        LIBSSH2_FREE(session, session->userauth_pswd_data);                        session->userauth_pswd_data = NULL;                        LIBSSH2_FREE(session, session->userauth_pswd_newpw);                        session->userauth_pswd_newpw = NULL;                         if (rc) {                            return _libssh2_error(session,                                                  LIBSSH2_ERROR_SOCKET_SEND,                                                  "Unable to send userauth "                                                  "password-change request");                        }                         /*                         * Ugliest use of goto ever.  Blame it on the                         * askN => requirev migration.                         */                        session->userauth_pswd_state = libssh2_NB_state_sent;                        goto password_response;                    }                }            } else {                session->userauth_pswd_state = libssh2_NB_state_idle;                return _libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED,                                      "Password Expired, and no callback "                                      "specified");            }        }    }     /* FAILURE */    LIBSSH2_FREE(session, session->userauth_pswd_data);    session->userauth_pswd_data = NULL;    session->userauth_pswd_state = libssh2_NB_state_idle;     return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED,                          "Authentication failed");} /* * libssh2_userauth_password_ex * * Plain ol' login */ LIBSSH2_API intlibssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username,                             unsigned int username_len, const char *password,                             unsigned int password_len,                             LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))){    int rc;    BLOCK_ADJUST(rc, session,                 userauth_password(session, username, username_len,                                   (unsigned char *)password, password_len,                                   passwd_change_cb));    return rc;} /* * file_read_publickey * * Read a public key from an id_???.pub style file * * Returns an allocated string containing the decoded key in *pubkeydata * on success. * Returns an allocated string containing the key method (e.g. "ssh-dss") * in method on success. */static intfile_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,                    size_t *method_len,                    unsigned char **pubkeydata,                    size_t *pubkeydata_len,                    const char *pubkeyfile){    FILE *fd;    char c;    unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;    size_t pubkey_len = 0;    unsigned int tmp_len;     _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s",                   pubkeyfile);    /* Read Public Key */    fd = fopen(pubkeyfile, "r");    if (!fd) {        return _libssh2_error(session, LIBSSH2_ERROR_FILE,                              "Unable to open public key file");    }    while (!feof(fd) && 1 == fread(&c, 1, 1, fd) && c != '\r' && c != '\n')        pubkey_len++;    if (feof(fd)) {        /* the last character was EOF */        pubkey_len--;    }    rewind(fd);     if (pubkey_len <= 1) {        fclose(fd);        return _libssh2_error(session, LIBSSH2_ERROR_FILE,                              "Invalid data in public key file");    }     pubkey = LIBSSH2_ALLOC(session, pubkey_len);    if (!pubkey) {        fclose(fd);        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,                              "Unable to allocate memory for public key data");    }    if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) {        LIBSSH2_FREE(session, pubkey);        fclose(fd);        return _libssh2_error(session, LIBSSH2_ERROR_FILE,                              "Unable to read public key from file");    }

Lines 1–500 of 1687.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t