GNURLOPT_SSH_KEYFUNCTION(3)
π GNURLOPT_SSH_KEYFUNCTION β bestie, this is your known-hosts vibe check π¦
ok so real talk, this page is from the curl_easy_setopt options fam, and it's literally the CURLOPT_SSH_KEYFUNCTION era of your life. Let's get into it, no cap.
β¨ NAME β¨
CURLOPT_SSH_KEYFUNCTION β the callback for known host matching logic. yeah. it's the "so what do we do about this host" hotline π₯
π SYNOPSIS π
ok first of all, the include. it's giving gnurl. not curl. gnurl. iykyk π
#include <gnurl/curl.h>
enum curl_khstat {
CURLKHSTAT_FINE_ADD_TO_FILE,
CURLKHSTAT_FINE,
CURLKHSTAT_REJECT, /* reject the connection, return an error */
CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right
now so this causes a CURLE_DEFER error but
otherwise the connection will be left intact
etc */
};
enum curl_khmatch {
CURLKHMATCH_OK, /* match */
CURLKHMATCH_MISMATCH, /* host found, key mismatch! */
CURLKHMATCH_MISSING, /* no matching host/key found */
};
struct curl_khkey {
const char *key; /* points to a null-terminated string encoded with
base64 if len is zero, otherwise to the "raw"
data */
size_t len;
enum curl_khtype keytype;
};
int ssh_keycallback(CURL *easy,
const struct curl_khkey *knownkey,
const struct curl_khkey *foundkey,
enum curl_khmatch,
void *clientp);
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_KEYFUNCTION,
ssh_keycallback);
like, look at that prototype. that's your callback's whole job description π«Ά
πΈ DESCRIPTION πΈ
ok so you're gonna pass a pointer to your callback function, and it has to match the prototype up there. periodt.
it gets called when the known_host matching has been done β so basically once libcurl has done the vibe check, it hits you up to let you act on it and decide how libcurl should proceed. and important: the callback will only be called if CURLOPT_SSH_KNOWNHOSTS(3) is also set. so like, no known_hosts, no call. that's the rule π
so what does your callback get handed? a whole little gift bag:
- the
CURLhandle knownkeyβ the key from theknown_hostsfilefoundkeyβ the key from the remote site- info from libcurl on the matching status
- a custom pointer (the one you set with
CURLOPT_SSH_KEYDATA(3))
and it MUST return one of the following return codes to tell libcurl how to act. must. like, capital M must. don't leave your girl hanging π
CURLKHSTAT_FINE_ADD_TO_FILE
the host+key is accepted, and libcurl will append it to the known_hosts file before continuing with the connection. it'll also add the host+key combo to the known_host pool kept in memory if it wasn't already there. π
β οΈ ok heads up though: the adding of data to the file is done by completely replacing the file with a new copy, so the permissions of the file must allow this. if they don't, that's a you problem, bestie.
CURLKHSTAT_FINE
the host+key is accepted, libcurl will continue with the connection. it'll also add the host+key combo to the known_host pool kept in memory if it wasn't already in there. so like, FINE is FINE_ADD_TO_FILE's chill sibling who doesn't touch the actual file β¨
CURLKHSTAT_REJECT
the host+key is rejected. libcurl will deny the connection from continuing and it will be closed. bye bestie ππ
CURLKHSTAT_DEFER
the host+key is rejected, but the SSH connection is asked to be kept alive. π«Ά
this one's for when the app wants to somehow return back and act on the host+key situation, and then retry without needing the overhead of setting it all up from scratch again. iconic lazy-genius behavior honestly.
π¦ DEFAULT π¦
NULL
as in, nothing. nada. the void. π³οΈ
π§ PROTOCOLS π§
SFTP and SCP β that's it, that's the list β¨
π EXAMPLE π
ok here's the callback, looking all responsible:
static int keycb(CURL *easy,
const struct curl_khkey *knownkey,
const struct curl_khkey *foundkey,
enum curl_khmatch,
void *clientp)
{
/* 'clientp' points to the callback_data struct */
/* investigate the situation and return the correct value */
return CURLKHSTAT_FINE_ADD_TO_FILE;
}
and then the actual setup part, where you wire it all up:
{
curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/thisfile.txt");
curl_easy_setopt(curl, CURLOPT_SSH_KEYFUNCTION, keycb);
curl_easy_setopt(curl, CURLOPT_SSH_KEYDATA, &callback_data);
curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, "/home/user/known_hosts");
curl_easy_perform(curl);
}
see how CURLOPT_SSH_KNOWNHOSTS is right there? because remember, no known_hosts = no callback. main character energy requires the supporting cast π¬
π AVAILABILITY π
added in 7.19.6. vintage but still slaying β
π RETURN VALUE π
returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. simple as that, ngl.
π SEE ALSO π
go read those too, they're literally the other half of this story π«Ά
and that's the page!! π this whole thing came to you courtesy of libcurl 7.37.0, dated 19 Jun 2014, living its best life under the GNURLOPT_SSH_KEYFUNCTION(3) name. mwah π β¨
π¦ where this page comes from
- nixos 26.05: libgnurl 7.72.0
- nixpkgs unstable: libgnurl 7.72.0
- Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms