aboutsummaryrefslogtreecommitdiffstats
path: root/lib/url.c
blob: de9966b49304fc8aeac6246b581fa0cebbb99c85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  /********************************************************************\
  * BitlBee -- An IRC to other IM-networks gateway                     *
  *                                                                    *
  * Copyright 2001-2005 Wilmer van der Gaast and others                *
  \********************************************************************/

/* URL/mirror stuff - Stolen from Axel                                  */

/*
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License with
  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
  Suite 330, Boston, MA  02111-1307  USA
*/

#include "url.h"

/* Convert an URL to a url_t structure */
int url_set( url_t *url, char *set_url )
{
	char s[MAX_STRING+1];
	char *i;
	
	memset( url, 0, sizeof( url_t ) );
	memset( s, 0, sizeof( s ) );
	
	/* protocol:// */
	if( ( i = strstr( set_url, "://" ) ) == NULL )
	{
		url->proto = PROTO_DEFAULT;
		strncpy( s, set_url, MAX_STRING );
	}
	else
	{
		if( g_strncasecmp( set_url, "http", i - set_url ) == 0 )
			url->proto = PROTO_HTTP;
		else if( g_strncasecmp( set_url, "https", i - set_url ) == 0 )
			url->proto = PROTO_HTTPS;
		else if( g_strncasecmp( set_url, "socks4", i - set_url ) == 0 )
			url->proto = PROTO_SOCKS4;
		else if( g_strncasecmp( set_url, "socks5", i - set_url ) == 0 )
			url->proto = PROTO_SOCKS5;
		else
			return 0;
		
		strncpy( s, i + 3, MAX_STRING );
	}
	
	/* Split */
	if( ( i = strchr( s, '/' ) ) == NULL )
	{
		strcpy( url->file, "/" );
	}
	else
	{
		strncpy( url->file, i, MAX_STRING );
		*i = 0;
	}
	strncpy( url->host, s, MAX_STRING );
	
	/* Check for username in host field */
	if( strrchr( url->host, '@' ) != NULL )
	{
		strncpy( url->user, url->host, MAX_STRING );
		i = strrchr( url->user, '@' );
		*i = 0;
		strcpy( url->host, i + 1 );
		*url->pass = 0;
	}
	/* If not: Fill in defaults */
	else
	{
		*url->user = *url->pass = 0;
	}
	
	/* Password? */
	if( ( i = strchr( url->user, ':' ) ) != NULL )
	{
		*i = 0;
		strcpy( url->pass, i + 1 );
	}
	/* Port number? */
	if( ( i = strchr( url->host, ':' ) ) != NULL )
	{
		*i = 0;
		sscanf( i + 1, "%d", &url->port );
	}
	else
	{
		if( url->proto == PROTO_HTTP )
			url->port = 80;
		else if( url->proto == PROTO_HTTPS )
			url->port = 443;
		else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS5 )
			url->port = 1080;
	}
	
	return( url->port > 0 );
}
lass="n">SHA1_HASH_SIZE); s = g_realloc(s, strlen(s) * 3 + 1); http_encode(s); return s; } static char *oauth_nonce() { unsigned char bytes[21]; random_bytes(bytes, sizeof(bytes)); return base64_encode(bytes, sizeof(bytes)); } void oauth_params_add(GSList **params, const char *key, const char *value) { char *item; if (!key || !value) { return; } item = g_strdup_printf("%s=%s", key, value); *params = g_slist_insert_sorted(*params, item, (GCompareFunc) strcmp); } void oauth_params_del(GSList **params, const char *key) { int key_len = strlen(key); GSList *l, *n; if (!params) { return; } for (l = *params; l; l = n) { n = l->next; char *data = l->data; if (strncmp(data, key, key_len) == 0 && data[key_len] == '=') { *params = g_slist_remove(*params, data); g_free(data); } } } void oauth_params_set(GSList **params, const char *key, const char *value) { oauth_params_del(params, key); oauth_params_add(params, key, value); } const char *oauth_params_get(GSList **params, const char *key) { int key_len = strlen(key); GSList *l; if (params == NULL) { return NULL; } for (l = *params; l; l = l->next) { if (strncmp((char *) l->data, key, key_len) == 0 && ((char *) l->data)[key_len] == '=') { return (const char *) l->data + key_len + 1; } } return NULL; } void oauth_params_parse(GSList **params, char *in) { char *amp, *eq, *s; while (in && *in) { eq = strchr(in, '='); if (!eq) { break; } *eq = '\0'; if ((amp = strchr(eq + 1, '&'))) { *amp = '\0'; } s = g_strdup(eq + 1); http_decode(s); oauth_params_add(params, in, s); g_free(s); *eq = '='; if (amp == NULL) { break; } *amp = '&'; in = amp + 1; } } void oauth_params_free(GSList **params) { while (params && *params) { g_free((*params)->data); *params = g_slist_remove(*params, (*params)->data); } } char *oauth_params_string(GSList *params) { GSList *l; GString *str = g_string_new(""); for (l = params; l; l = l->next) { char *s, *eq; s = g_malloc(strlen(l->data) * 3 + 1); strcpy(s, l->data); if ((eq = strchr(s, '='))) { http_encode(eq + 1); } g_string_append(str, s); g_free(s); if (l->next) { g_string_append_c(str, '&'); } } return g_string_free(str, FALSE); } void oauth_info_free(struct oauth_info *info) { if (info) { g_free(info->auth_url); g_free(info->request_token); g_free(info->token); g_free(info->token_secret); oauth_params_free(&info->params); g_free(info); } } static void oauth_add_default_params(GSList **params, const struct oauth_service *sp) { char *s; oauth_params_set(params, "oauth_consumer_key", sp->consumer_key); oauth_params_set(params, "oauth_signature_method", "HMAC-SHA1"); s = g_strdup_printf("%d", (int) time(NULL)); oauth_params_set(params, "oauth_timestamp", s); g_free(s); s = oauth_nonce(); oauth_params_set(params, "oauth_nonce", s); g_free(s); oauth_params_set(params, "oauth_version", "1.0"); } static void *oauth_post_request(const char *url, GSList **params_, http_input_function func, struct oauth_info *oi) { GSList *params = NULL; char *s, *params_s, *post; void *req; url_t url_p; if (!url_set(&url_p, url)) { oauth_params_free(params_); return NULL; } if (params_) { params = *params_; } oauth_add_default_params(&params, oi->sp); params_s = oauth_params_string(params); oauth_params_free(&params); s = oauth_sign("POST", url, params_s, oi); post = g_strdup_printf("%s&oauth_signature=%s", params_s, s); g_free(params_s); g_free(s); s = g_strdup_printf("POST %s HTTP/1.0\r\n" "Host: %s\r\n" "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %zd\r\n" "\r\n" "%s", url_p.file, url_p.host, strlen(post), post); g_free(post); req = http_dorequest(url_p.host, url_p.port, url_p.proto == PROTO_HTTPS, s, func, oi); g_free(s); return req; } static void oauth_request_token_done(struct http_request *req); struct oauth_info *oauth_request_token(const struct oauth_service *sp, oauth_cb func, void *data) { struct oauth_info *st = g_new0(struct oauth_info, 1); GSList *params = NULL; st->func = func; st->data = data; st->sp = sp; oauth_params_add(&params, "oauth_callback", "oob"); if (!oauth_post_request(sp->url_request_token, &params, oauth_request_token_done, st)) { oauth_info_free(st); return NULL; } return st; } static void oauth_request_token_done(struct http_request *req) { struct oauth_info *st = req->data; st->http = req; if (req->status_code == 200) { GSList *params = NULL; st->auth_url = g_strdup_printf("%s?%s", st->sp->url_authorize, req->reply_body); oauth_params_parse(&params, req->reply_body); st->request_token = g_strdup(oauth_params_get(&params, "oauth_token")); st->token_secret = g_strdup(oauth_params_get(&params, "oauth_token_secret")); oauth_params_free(&params); } st->stage = OAUTH_REQUEST_TOKEN; st->func(st); } static void oauth_access_token_done(struct http_request *req); gboolean oauth_access_token(const char *pin, struct oauth_info *st) { GSList *params = NULL; oauth_params_add(&params, "oauth_token", st->request_token); oauth_params_add(&params, "oauth_verifier", pin); return oauth_post_request(st->sp->url_access_token, &params, oauth_access_token_done, st) != NULL; } static void oauth_access_token_done(struct http_request *req) { struct oauth_info *st = req->data; st->http = req; if (req->status_code == 200) { oauth_params_parse(&st->params, req->reply_body); st->token = g_strdup(oauth_params_get(&st->params, "oauth_token")); g_free(st->token_secret); st->token_secret = g_strdup(oauth_params_get(&st->params, "oauth_token_secret")); } st->stage = OAUTH_ACCESS_TOKEN; if (st->func(st)) { /* Don't need these anymore, but keep the rest. */ g_free(st->auth_url); st->auth_url = NULL; g_free(st->request_token); st->request_token = NULL; oauth_params_free(&st->params); } } char *oauth_http_header(struct oauth_info *oi, const char *method, const char *url, char *args) { GSList *params = NULL, *l; char *sig = NULL, *params_s, *s; GString *ret = NULL; oauth_params_add(&params, "oauth_token", oi->token); oauth_add_default_params(&params, oi->sp); /* Start building the OAuth header. 'key="value", '... */ ret = g_string_new("OAuth "); for (l = params; l; l = l->next) { char *kv = l->data; char *eq = strchr(kv, '='); char esc[strlen(kv) * 3 + 1]; if (eq == NULL) { break; /* WTF */ } strcpy(esc, eq + 1); http_encode(esc); g_string_append_len(ret, kv, eq - kv + 1); g_string_append_c(ret, '"'); g_string_append(ret, esc); g_string_append(ret, "\", "); } /* Now, before generating the signature, add GET/POST arguments to params since they should be included in the base signature string (but not in the HTTP header). */ if (args) { oauth_params_parse(&params, args); } if ((s = strchr(url, '?'))) { s = g_strdup(s + 1); oauth_params_parse(&params, s); g_free(s); } /* Append the signature and we're done! */ params_s = oauth_params_string(params); sig = oauth_sign(method, url, params_s, oi); g_string_append_printf(ret, "oauth_signature=\"%s\"", sig); g_free(params_s); oauth_params_free(&params); g_free(sig); return ret ? g_string_free(ret, FALSE) : NULL; } char *oauth_to_string(struct oauth_info *oi) { GSList *params = NULL; char *ret; oauth_params_add(&params, "oauth_token", oi->token); oauth_params_add(&params, "oauth_token_secret", oi->token_secret); ret = oauth_params_string(params); oauth_params_free(&params); return ret; } struct oauth_info *oauth_from_string(char *in, const struct oauth_service *sp) { struct oauth_info *oi = g_new0(struct oauth_info, 1); GSList *params = NULL; oauth_params_parse(&params, in); oi->token = g_strdup(oauth_params_get(&params, "oauth_token")); oi->token_secret = g_strdup(oauth_params_get(&params, "oauth_token_secret")); oauth_params_free(&params); oi->sp = sp; return oi; }