Exemple #1
0
/* {{{ libssh2_comp_method_zlib_comp
 * zlib, a compression standard for all occasions
 */
static int
libssh2_comp_method_zlib_comp(LIBSSH2_SESSION * session,
                              int compress,
                              unsigned char **dest,
                              unsigned long *dest_len,
                              unsigned long payload_limit,
                              int *free_dest,
                              const unsigned char *src,
                              unsigned long src_len, void **abstract)
{
    z_stream *strm = *abstract;
    /* A short-term alloc of a full data chunk is better than a series of
       reallocs */
    char *out;
    int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
    int limiter = 0;

    /* In practice they never come smaller than this */
    if (out_maxlen < 25) {
        out_maxlen = 25;
    }

    if (out_maxlen > (int) payload_limit) {
        out_maxlen = payload_limit;
    }

    strm->next_in = (unsigned char *) src;
    strm->avail_in = src_len;
    strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
    out = (char *) strm->next_out;
    strm->avail_out = out_maxlen;
    if (!strm->next_out) {
        libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                      "Unable to allocate compression/decompression buffer",
                      0);
        return -1;
    }
    while (strm->avail_in) {
        int status;

        if (compress) {
            status = deflate(strm, Z_PARTIAL_FLUSH);
        } else {
            status = inflate(strm, Z_PARTIAL_FLUSH);
        }
        if (status != Z_OK) {
            libssh2_error(session, LIBSSH2_ERROR_ZLIB,
                          "compress/decompression failure", 0);
            LIBSSH2_FREE(session, out);
            return -1;
        }
        if (strm->avail_in) {
            unsigned long out_ofs = out_maxlen - strm->avail_out;
            char *newout;

            out_maxlen +=
                compress ? (strm->avail_in + 4) : (2 * strm->avail_in);

            if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
                libssh2_error(session, LIBSSH2_ERROR_ZLIB,
                              "Excessive growth in decompression phase", 0);
                LIBSSH2_FREE(session, out);
                return -1;
            }

            newout = LIBSSH2_REALLOC(session, out, out_maxlen);
            if (!newout) {
                libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                              "Unable to expand compress/decompression buffer",
                              0);
                LIBSSH2_FREE(session, out);
                return -1;
            }
            out = newout;
            strm->next_out = (unsigned char *) out + out_ofs;
            strm->avail_out +=
                compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
        } else
            while (!strm->avail_out) {
                /* Done with input, might be a byte or two in internal buffer during compress
                 * Or potentially many bytes if it's a decompress
                 */
                int grow_size = compress ? 8 : 1024;
                char *newout;

                if (out_maxlen >= (int) payload_limit) {
                    libssh2_error(session, LIBSSH2_ERROR_ZLIB,
                                  "Excessive growth in decompression phase",
                                  0);
                    LIBSSH2_FREE(session, out);
                    return -1;
                }

                if (grow_size > (int) (payload_limit - out_maxlen)) {
                    grow_size = payload_limit - out_maxlen;
                }

                out_maxlen += grow_size;
                strm->avail_out = grow_size;

                newout = LIBSSH2_REALLOC(session, out, out_maxlen);
                if (!newout) {
                    libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                                  "Unable to expand final compress/decompress buffer",
                                  0);
                    LIBSSH2_FREE(session, out);
                    return -1;
                }
                out = newout;
                strm->next_out = (unsigned char *) out + out_maxlen -
                    grow_size;

                if (compress) {
                    status = deflate(strm, Z_PARTIAL_FLUSH);
                } else {
                    status = inflate(strm, Z_PARTIAL_FLUSH);
                }
                if (status != Z_OK) {
                    libssh2_error(session, LIBSSH2_ERROR_ZLIB,
                                  "compress/decompression failure", 0);
                    LIBSSH2_FREE(session, out);
                    return -1;
                }
            }
    }

    *dest = (unsigned char *) out;
    *dest_len = out_maxlen - strm->avail_out;
    *free_dest = 1;

    return 0;
}
Exemple #2
0
/* {{{ libssh2_userauth_publickey_fromfile_ex
 * Authenticate using a keypair found in the named files
 */
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
                                                                                 const char *publickey, const char *privatekey,
                                                                                 const char *passphrase)
{
	LIBSSH2_HOSTKEY_METHOD *privkeyobj;
	void *abstract;
	unsigned char buf[5];
	struct iovec datavec[4];
	unsigned char *method, *pubkeydata, *packet, *s, *b, *sig, *data;
	unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PK_OK, 0 };
	unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;

	if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
		return -1;
	}

	packet_len = username_len + method_len + pubkeydata_len + 45;	/* packet_type(1) + username_len(4) + servicename_len(4) + 
																	   service_name(14)"ssh-connection" + authmethod_len(4) + 
																	   authmethod(9)"publickey" + sig_included(1)'\0' + 
																	   algmethod_len(4) + publickey_len(4) */
	/* Preallocate space for an overall length,  method name again,
	 * and the signature, which won't be any larger than the size of the publickeydata itself */
	s = packet = LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));

	*(s++) = SSH_MSG_USERAUTH_REQUEST;
	libssh2_htonu32(s, username_len);				s += 4;
	memcpy(s, username, username_len);				s += username_len;

	libssh2_htonu32(s, 14);							s += 4;
	memcpy(s, "ssh-connection", 14);				s += 14;

	libssh2_htonu32(s, 9);							s += 4;
	memcpy(s, "publickey", 9);						s += 9;

	b = s;
	*(s++) = 0; /* Not sending signature with *this* packet */

	libssh2_htonu32(s, method_len);					s += 4;
	memcpy(s, method, method_len);					s += method_len;

	libssh2_htonu32(s, pubkeydata_len);				s += 4;
	memcpy(s, pubkeydata, pubkeydata_len);			s += pubkeydata_len;

#ifdef LIBSSH2_DEBUG_USERAUTH
	_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication");
#endif
	if (libssh2_packet_write(session, packet, packet_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
		LIBSSH2_FREE(session, packet);
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, pubkeydata);
		return -1;
	}

	if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
		LIBSSH2_FREE(session, packet);
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, pubkeydata);
		return -1;
	}

	if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
		_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Pubkey authentication prematurely successful");
#endif
		/* God help any SSH server that allows an UNVERIFIED public key to validate the user */
		LIBSSH2_FREE(session, data);
		LIBSSH2_FREE(session, packet);
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, pubkeydata);
		session->state |= LIBSSH2_STATE_AUTHENTICATED;
		return 0;
	}

	if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
		/* This public key is not allowed for this user on this server */
		LIBSSH2_FREE(session, data);
		LIBSSH2_FREE(session, packet);
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, pubkeydata);
		libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
		return -1;
	}

	/* Semi-Success! */
	LIBSSH2_FREE(session, data);
	LIBSSH2_FREE(session, pubkeydata);

	if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, (const char *)method, method_len, privatekey, passphrase)) {
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, packet);
		return -1;
	}

	*b = 0xFF;

	libssh2_htonu32(buf, session->session_id_len);
	datavec[0].iov_base = buf;
	datavec[0].iov_len = 4;
	datavec[1].iov_base = session->session_id;
	datavec[1].iov_len = session->session_id_len;
	datavec[2].iov_base = packet;
	datavec[2].iov_len = packet_len;

	if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, packet);
		if (privkeyobj->dtor) {
			privkeyobj->dtor(session, &abstract);
		}
		return -1;
	}

	if (privkeyobj->dtor) {
		privkeyobj->dtor(session, &abstract);
	}

	if (sig_len > pubkeydata_len) {
		/* Should *NEVER* happen, but...well.. better safe than sorry */
		packet = LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
		if (!packet) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-publickey packet", 0);
			LIBSSH2_FREE(session, method);
			return -1;
		}
	}

	s = packet + packet_len;

	libssh2_htonu32(s, 4 + method_len + 4 + sig_len);	s += 4;

	libssh2_htonu32(s, method_len);						s += 4;
	memcpy(s, method, method_len);						s += method_len;
	LIBSSH2_FREE(session, method);

	libssh2_htonu32(s, sig_len);						s += 4;
	memcpy(s, sig, sig_len);							s += sig_len;
	LIBSSH2_FREE(session, sig);

#ifdef LIBSSH2_DEBUG_USERAUTH
	_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication -- phase 2");
#endif
	if (libssh2_packet_write(session, packet, s - packet)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
		LIBSSH2_FREE(session, packet);
		return -1;
	}
	LIBSSH2_FREE(session, packet);

	/* PK_OK is no longer valid */
	reply_codes[2] = 0;

	if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
		return -1;
	}

	if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
		_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Publickey authentication successful");
#endif
		/* We are us and we've proved it. */
		LIBSSH2_FREE(session, data);
		session->state |= LIBSSH2_STATE_AUTHENTICATED;
		return 0;
	}

	/* This public key is not allowed for this user on this server */
	LIBSSH2_FREE(session, data);
	libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
	return -1;
}
Exemple #3
0
/* {{{ libssh2_publickey_list_fetch
 * Fetch a list of supported public key from a server
 */
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list)
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	libssh2_publickey_list *list = NULL;
	unsigned char *s, buffer[12], *data = NULL;
	unsigned long buffer_len = 12, keys = 0, max_keys = 0, data_len, i, response;
	/*	packet_len(4) + 
		list_len(4) +
		"list"(4) */

	s = buffer;
	libssh2_htonu32(s, buffer_len - 4);							s += 4;
	libssh2_htonu32(s, sizeof("list") - 1);						s += 4;
	memcpy(s, "list", sizeof("list") - 1);						s += sizeof("list") - 1;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
#endif
    if ((s - buffer) != libssh2_channel_write(channel, buffer, (s - buffer))) {
        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
		return -1;
    }

	while (1) {
		if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
			goto err_exit;
		}

		s = data;
		if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
			libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
			goto err_exit;
		}

		switch (response) {
			case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
			/* Error, or processing complete */
			{
				unsigned long status, descr_len, lang_len;
				unsigned char *descr, *lang;
				
				status = libssh2_ntohu32(s);					s += 4;
				descr_len = libssh2_ntohu32(s);					s += 4;
				descr = s;										s += descr_len;
				lang_len = libssh2_ntohu32(s);					s += 4;
				lang = s;										s += lang_len;

				if (s > data + data_len) {
					libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
					goto err_exit;
				}

				if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
					LIBSSH2_FREE(session, data);
					*pkey_list = list;
					*num_keys = keys;
					return 0;
				}

				libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
				goto err_exit;
			}
			case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
				/* What we want */
				if (keys >= max_keys) {
					/* Grow the key list if necessary */
					max_keys += 8;
					list = LIBSSH2_REALLOC(session, list, (max_keys + 1) * sizeof(libssh2_publickey_list));
					if (!list) {
						libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey list", 0);
						goto err_exit;
					}
				}
				if (pkey->version == 1) {
					unsigned long comment_len;

					comment_len = libssh2_ntohu32(s);								s += 4;
					if (comment_len) {
						list[keys].num_attrs = 1;
						list[keys].attrs = LIBSSH2_ALLOC(session, sizeof(libssh2_publickey_attribute));
						if (!list[keys].attrs) {
							libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
							goto err_exit;
						}
						list[keys].attrs[0].name = "comment";
						list[keys].attrs[0].name_len = sizeof("comment") - 1;
						list[keys].attrs[0].value = s;
						list[keys].attrs[0].value_len = comment_len;
						list[keys].attrs[0].mandatory = 0;

						s += comment_len;
					} else {
						list[keys].num_attrs = 0;
						list[keys].attrs = NULL;
					}
					list[keys].name_len = libssh2_ntohu32(s);						s += 4;
					list[keys].name = s;											s += list[keys].name_len;
					list[keys].blob_len = libssh2_ntohu32(s);						s += 4;
					list[keys].blob = s;											s += list[keys].blob_len;
				} else {
					/* Version == 2 */
					list[keys].name_len = libssh2_ntohu32(s);						s += 4;
					list[keys].name = s;											s += list[keys].name_len;
					list[keys].blob_len = libssh2_ntohu32(s);						s += 4;
					list[keys].blob = s;											s += list[keys].blob_len;
					list[keys].num_attrs = libssh2_ntohu32(s);						s += 4;
					if (list[keys].num_attrs) {
						list[keys].attrs = LIBSSH2_ALLOC(session, list[keys].num_attrs * sizeof(libssh2_publickey_attribute));
						if (!list[keys].attrs) {
							libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
							goto err_exit;
						}
						for(i = 0; i < list[keys].num_attrs; i++) {
							list[keys].attrs[i].name_len = libssh2_ntohu32(s);			s += 4;
							list[keys].attrs[i].name = s;								s += list[keys].attrs[i].name_len;
							list[keys].attrs[i].value_len = libssh2_ntohu32(s);			s += 4;
							list[keys].attrs[i].value = s;								s += list[keys].attrs[i].value_len;
							list[keys].attrs[i].mandatory = 0;	/* actually an ignored value */
						}
					} else {
						list[keys].attrs = NULL;
					}
				}
				list[keys].packet = data; /* To be FREEd in libssh2_publickey_list_free() */
				keys++;

				list[keys].packet = NULL; /* Terminate the list */
				data = NULL;
				break;
			default:
				/* Unknown/Unexpected */
				libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
				LIBSSH2_FREE(session, data);
		}
	}

	/* Only reached via explicit goto */
 err_exit:
	if (data) {
		LIBSSH2_FREE(session, data);
	}
	if (list) {
		libssh2_publickey_list_free(pkey, list);
	}
	return -1;
}
Exemple #4
0
int _libssh2_pem_parse (LIBSSH2_SESSION *session,
			const char *headerbegin,
			const char *headerend,
			FILE *fp,
			char **data, unsigned int *datalen)
{
	char line[LINE_SIZE];
	char *b64data = NULL;
	unsigned int b64datalen = 0;
	int ret;

	do
	{
		if (readline(line, LINE_SIZE, fp))
		{
			return -1;
		}
	}
	while (strcmp (line, headerbegin) != 0);

	*line = '\0';

	do
	{
		if (*line)
		{
			char *tmp;
			size_t linelen;

			linelen = strlen (line);
			tmp = LIBSSH2_REALLOC (session, b64data,
					       b64datalen + linelen);
			if (!tmp)
			{
				ret = -1;
				goto out;
			}
			memcpy (tmp + b64datalen, line, linelen);
			b64data = tmp;
			b64datalen += linelen;
		}

		if (readline(line, LINE_SIZE, fp))
		{
			ret = -1;
			goto out;
		}
	} while (strcmp (line, headerend) != 0);

	if (libssh2_base64_decode(session, data, datalen,
				  b64data, b64datalen))
	{
		ret = -1;
		goto out;
	}

	ret = 0;
out:
	if (b64data) {
		LIBSSH2_FREE (session, b64data);
	}
	return ret;
}
Exemple #5
0
static char *
convert_ccsid(LIBSSH2_SESSION *session, libssh2_string_cache **cache,
              unsigned short outccsid, unsigned short inccsid,
              const char *instring, ssize_t inlen, size_t *outlen)
{
    char *inp;
    char *outp;
    size_t olen;
    size_t ilen;
    size_t buflen;
    size_t curlen;
    ssize_t termsize;
    int i;
    char *dst;
    libssh2_string_cache *outstring;
    QtqCode_T incode;
    QtqCode_T outcode;
    iconv_t cd;

    if (!instring) {
        if (outlen)
            *outlen = 0;
        return NULL;
    }
    if (outlen)
        *outlen = -1;
    if (!session || !cache)
        return NULL;

    /* Get terminator size. */
    termsize = terminator_size(outccsid);
    if (termsize < 0)
        return NULL;
 
    /* Prepare conversion parameters. */
    memset((void *) &incode, 0, sizeof incode);
    memset((void *) &outcode, 0, sizeof outcode);
    incode.CCSID = inccsid;
    outcode.CCSID = outccsid;
    curlen = OFFSET_OF(libssh2_string_cache, string);
    inp = (char *) instring;
    ilen = inlen;
    buflen = inlen + curlen;
    if (inlen < 0) {
        incode.length_option = 1;
        buflen = STRING_GRANULE;
        ilen = 0;
    }

    /* Allocate output string buffer and open conversion descriptor. */
    dst = LIBSSH2_ALLOC(session, buflen + termsize);
    if (!dst)
        return NULL;
    cd = QtqIconvOpen(&outcode, &incode);
    if (cd.return_value == -1) {
        LIBSSH2_FREE(session, (char *) dst);
        return NULL;
    }

    /* Convert string. */
    for (;;) {
        outp = dst + curlen;
        olen = buflen - curlen;
        i = iconv(cd, &inp, &ilen, &outp, &olen);
        if (inlen < 0 && olen == buflen - curlen) {
            /* Special case: converted 0-length (sub)strings do not store the
               terminator. */
            if (termsize) {
                memset(outp, 0, termsize);
                olen -= termsize;
            }
        }
        curlen = buflen - olen;
        if (i >= 0 || errno != E2BIG)
            break;
        /* Must expand buffer. */
        buflen += STRING_GRANULE;
        outp = LIBSSH2_REALLOC(session, dst, buflen + termsize);
        if (!outp)
            break;
        dst = outp;
    }

    iconv_close(cd);

    /* Check for error. */
    if (i < 0 || !outp) {
        LIBSSH2_FREE(session, dst);
        return NULL;
    }

    /* Process terminator. */
    if (inlen < 0)
        curlen -= termsize;
    else if (termsize)
        memset(dst + curlen, 0, termsize);

    /* Shorten buffer if possible. */
    if (curlen < buflen)
        dst = LIBSSH2_REALLOC(session, dst, curlen + termsize);

    /* Link to cache. */
    outstring = (libssh2_string_cache *) dst;
    outstring->next = *cache;
    *cache = outstring;

    /* Return length if required. */
    if (outlen)
        *outlen = curlen - OFFSET_OF(libssh2_string_cache, string);

    return outstring->string;
}