Skip to content

Commit

Permalink
http: call curl_global_init in parent and child processes
Browse files Browse the repository at this point in the history
Until now we have relied on curl_easy_init() calling curl_global_init()
for us and thus not worrying about when curl is initialized.

Unfortunately, on some platforms libcurl does not work properly
when initialized in one process, and then later accessed from
a child process.  The following case demonstrated the problem
on CentOS 6:

    cat fields.txt | ./lpass add --non-interactive --sync=now MyAccount

The uploader queue showed every connection failing with error 35:
unable to validate the connection certificate.

The --sync=now means the server will be contacted to refresh the blob,
in the parent process.  Then, the add itself will happen via the
lpass uploader in a child process.  When the sync runs, libcurl is
initialized in the parent.  When the child runs, libcurl inherits
stale global state from the parent that prevents it from operating
properly.  Reinitializing curl in the child fixes this.

Add a new function, http_init() which calls the curl destroy and init
functions.  These are reference-counted, so curl_global_destroy() must
be called in the child process before curl_global_init(); however,
curl_global_destroy() checks that init has been run first so we can
just always call both rather than having separate init and re-init
functions.

Fixes lastpass#166.

Signed-off-by: Bob Copeland <[email protected]>
  • Loading branch information
Bob Copeland committed May 20, 2016
1 parent f5f7e2a commit b78ae2e
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 0 deletions.
6 changes: 6 additions & 0 deletions http.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ void vhttp_post_add_params(struct http_param_set *param_set, va_list args)
*argv_ptr = 0;
}

int http_init()
{
curl_global_cleanup();
return curl_global_init(CURL_GLOBAL_DEFAULT);
}

void http_post_add_params(struct http_param_set *param_set, ...)
{
va_list args;
Expand Down
1 change: 1 addition & 0 deletions http.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct http_param_set
#define HTTP_ERROR_CODE CURLE_HTTP_RETURNED_ERROR
#define HTTP_ERROR_CONNECT CURLE_SSL_CONNECT_ERROR

int http_init();
void http_post_add_params(struct http_param_set *params, ...);
char *http_post_lastpass(const char *page, const struct session *session, size_t *len, ...);
char *http_post_lastpass_v(const char *server, const char *page, const struct session *session, size_t *len, char **argv);
Expand Down
3 changes: 3 additions & 0 deletions lpass.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ int main(int argc, char *argv[])
/* Do not remove this umask. Always keep at top. */
umask(0077);

if (http_init())
die("Unable to initialize curl");

load_saved_environment();

if (argc >= 2 && argv[1][0] != '-')
Expand Down
6 changes: 6 additions & 0 deletions upload-queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,12 @@ static void upload_queue_run(const struct session *session, unsigned const char
signal(SIGTERM, upload_queue_cleanup);
signal(SIGALRM, upload_queue_cleanup);
setvbuf(stdout, NULL, _IOLBF, 0);

if (http_init()) {
lpass_log(LOG_ERROR, "UQ: unable to restart curl\n");
_exit(EXIT_FAILURE);
}

lpass_log(LOG_DEBUG, "UQ: starting queue run\n");
upload_queue_upload_all(session, key);
lpass_log(LOG_DEBUG, "UQ: queue run complete\n");
Expand Down

0 comments on commit b78ae2e

Please sign in to comment.