int ssh_analyze_banner(ssh_session session, int server)
{
    const char *banner;
    const char *openssh;

    if (server) {
        banner = session->clientbanner;
    } else {
        banner = session->serverbanner;
    }

    if (banner == NULL) {
        ssh_set_error(session, SSH_FATAL, "Invalid banner");
        return -1;
    }

    /*
     * Typical banners e.g. are:
     *
     * SSH-1.5-openSSH_5.4
     * SSH-1.99-openSSH_3.0
     *
     * SSH-2.0-something
     * 012345678901234567890
     */
    if (strlen(banner) < 6 ||
        strncmp(banner, "SSH-", 4) != 0) {
          ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
          return -1;
    }

    SSH_LOG(SSH_LOG_RARE, "Analyzing banner: %s", banner);

    switch (banner[4]) {
        case '2':
            break;
        case '1':
            if (strlen(banner) > 6) {
                if (banner[6] == '9') {
                    break;
                }
            }
            FALL_THROUGH;
        default:
            ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
            return -1;
    }

    /* Make a best-effort to extract OpenSSH version numbers. */
    openssh = strstr(banner, "OpenSSH");
    if (openssh != NULL) {
        char *tmp = NULL;
        unsigned long int major = 0UL;
        unsigned long int minor = 0UL;

        /*
         * The banner is typical:
         * OpenSSH_5.4
         * 012345678901234567890
         */
        if (strlen(openssh) > 9) {
            major = strtoul(openssh + 8, &tmp, 10);
            if ((tmp == (openssh + 8)) ||
                ((errno == ERANGE) && (major == ULONG_MAX)) ||
                ((errno != 0) && (major == 0)) ||
                ((major < 1) || (major > 100))) {
                /* invalid major */
                goto done;
            }

            minor = strtoul(openssh + 10, &tmp, 10);
            if ((tmp == (openssh + 10)) ||
                ((errno == ERANGE) && (major == ULONG_MAX)) ||
                ((errno != 0) && (major == 0)) ||
                (minor > 100)) {
                /* invalid minor */
                goto done;
            }

            session->openssh = SSH_VERSION_INT(((int) major), ((int) minor), 0);

            SSH_LOG(SSH_LOG_RARE,
                    "We are talking to an OpenSSH client version: %lu.%lu (%x)",
                    major, minor, session->openssh);
        }
    }

done:
    return 0;
}
int ssh_analyze_banner(ssh_session session, int server)
{
    const char *banner;
    const char *openssh;

    if (server) {
        banner = session->clientbanner;
    } else {
        banner = session->serverbanner;
    }

    if (banner == NULL) {
        ssh_set_error(session, SSH_FATAL, "Invalid banner");
        return -1;
    }

     
    if (strlen(banner) < 6 ||
        strncmp(banner, "SSH-", 4) != 0) {
          ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
          return -1;
    }

    SSH_LOG(SSH_LOG_RARE, "Analyzing banner: %s", banner);

    switch (banner[4]) {
        case '2':
            break;
        case '1':
            if (strlen(banner) > 6) {
                if (banner[6] == '9') {
                    break;
                }
            }
            FALL_THROUGH;
        default:
            ssh_set_error(session, SSH_FATAL, "Protocol mismatch: %s", banner);
            return -1;
    }

     
    openssh = strstr(banner, "OpenSSH");
    if (openssh != NULL) {
        char *tmp = NULL;
        unsigned long int major = 0UL;
        unsigned long int minor = 0UL;

         
        if (strlen(openssh) > 9) {
            major = strtoul(openssh + 8, &tmp, 10);
            if ((tmp == (openssh + 8)) ||
                ((errno == ERANGE) && (major == ULONG_MAX)) ||
                ((errno != 0) && (major == 0)) ||
                ((major < 1) || (major > 100))) {
                 
                goto done;
            }

            minor = strtoul(openssh + 10, &tmp, 10);
            if ((tmp == (openssh + 10)) ||
                ((errno == ERANGE) && (major == ULONG_MAX)) ||
                ((errno != 0) && (major == 0)) ||
                (minor > 100)) {
                 
                goto done;
            }

            session->openssh = SSH_VERSION_INT(((int) major), ((int) minor), 0);

            SSH_LOG(SSH_LOG_RARE,
                    "We are talking to an OpenSSH client version: %lu.%lu (%x)",
                    major, minor, session->openssh);
        }
    }

done:
    return 0;
}