1 #include "system.h"
2 #include "util.h"
3 #include "configure.h"
4 #include "md5hl.h"
5 
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <time.h>
11 #include <stdarg.h>
12 #include <err.h>
13 #include <sys/types.h>
14 
15 #if defined(DEBUG4)
16 int		debug_level = 4;
17 #elif defined(DEBUG3)
18 int		debug_level = 3;
19 #elif defined(DEBUG2)
20 int		debug_level = 2;
21 elif defined(DEBUG1) || defined(DEBUG)
22 int		debug_level = 1;
23 #else
24 int		debug_level = 0;
25 #endif
26 #ifdef		HAVE_ICONV
27 iconv_t		utfenc,
28 		utfdec;
29 #endif		/* HAVE_ICONV */
30 
31 static char	hex2char(const char *hex);
32 
33 void
lj_free(void * ptr)34 lj_free(void *ptr)
35 {
36 	if (ptr)
37 		free(ptr);
38 }
39 
40 void *
lj_calloc(size_t nmemb,size_t size)41 lj_calloc(size_t nmemb, size_t size)
42 {
43 	void		*ret = NULL;
44 
45 	if ((ret = calloc(nmemb, size)) == NULL)
46 		lj_error("Memory allocation error\n");
47 	lj_debug(4, "calloc [%d] elements of size [%d] to [%p]\n",
48 		nmemb, size, ret);
49 	return ret;
50 }
51 
52 /* Eventually we should find where we are overflowing our buffer...but for
53  * now, we just add 10 bytes to whatever is requested
54  */
55 
56 void *
lj_malloc(size_t size)57 lj_malloc(size_t size)
58 {
59 	void		*ret = NULL;
60 
61 	if (((ret = calloc(size, 1)) == NULL))
62 		lj_error("Memory allocation error\n");
63 	lj_debug(4, "malloc [%d] to [%p]\n", size, ret);
64 	return ret;
65 }
66 
67 void *
lj_realloc(void * ptr,size_t size)68 lj_realloc(void *ptr, size_t size)
69 {
70 	void		*ret = NULL;
71 
72 	if (!ptr)
73 	{
74 		return lj_malloc(size);
75 	}
76 	else if (!size)
77 	{
78 		lj_debug(4, "realloc freeing [%p]\n", ptr);
79 		lj_free(ptr);
80 		return NULL;
81 	}
82 	else
83 	{
84 		if (!(ret = realloc(ptr, size)))
85 			lj_error("Memory allocation error\n");
86 		lj_debug(4, "realloc [%d] bytes to [%p]\n", size, ret);
87 		return ret;
88 	}
89 	return NULL;
90 }
91 
92 size_t
lj_parraylen(const void * const * const parray)93 lj_parraylen(const void * const * const parray)
94 {
95 	int             i;
96 
97 	for (i = 0; parray[i] != NULL; i++)
98 		/* DO NOTHING */;
99 	return (size_t) i;
100 }
101 
102 int
lj_urlencode(const char * inbound,char ** outbound)103 lj_urlencode(const char *inbound, char **outbound)
104 {
105 	char            *buffer;
106 	const char	*utf8;
107 	int             i, j, l;
108 
109 	utf8 = inbound;
110 #ifdef		HAVE_ICONV
111 	{
112 		char	*outbuf, *p;
113 		size_t	inlen, outlen;
114 		int	sum;
115 
116 		inlen = 1 + strlen(inbound);
117 		outlen = 4 * inlen;
118 		p = lj_malloc(outlen);
119 		outbuf = p;
120 		sum = iconv(utfenc, &inbound, &inlen, &outbuf, &outlen);
121 		if (-1 == sum)
122 		{
123 			perror("Cannot convert");
124 			free(p);
125 			return 1;
126 		}
127 		utf8 = p;
128 	}
129 #endif		/* HAVE_ICONV */
130 
131 	buffer = lj_malloc(strlen(utf8) * 3 + 1);
132 	for (i = j = 0, l = strlen(utf8); i < l; i++)
133 	{
134 		if (((utf8[i] >= 'a') && (utf8[i] <= 'z'))
135 		    || ((utf8[i] >= 'A') && (utf8[i] <= 'Z'))
136 		    || ((utf8[i] >= '0') && (utf8[i] <= '9'))
137 		    || (utf8[i] < 0))
138 		{
139 			buffer[j] = utf8[i];
140 			j++;
141 		} else if (utf8[i] == ' ')
142 		{
143 			buffer[j] = '+';
144 			j++;
145 		} else
146 		{
147 			sprintf(&buffer[j], "%%%02X", utf8[i]);
148 			j += 3;
149 		}
150 	}
151 	buffer[j] = '\0';
152 
153 	*outbound = NULL;
154 	*outbound = lj_realloc(*outbound, strlen(buffer) + 1);
155 	strcpy(*outbound, buffer);
156 	free(buffer);
157 	return 0;
158 }
159 
160 int
lj_chardecode(const char * inbound,char * outbound)161 lj_chardecode(const char *inbound, char *outbound)
162 {
163 #ifdef		HAVE_ICONV
164 		size_t		inlen = strlen(inbound) + 1,
165 				outlen = LJ_BUFFER_MAX,
166 				sum;
167 		const char	*inbuf = inbound;
168 		char		*outbuf = outbound;
169 
170 		sum = iconv(utfdec, &inbuf, &inlen, &outbuf, &outlen);
171 		if ((size_t)-1 == sum)
172 		{
173 			lj_debug(1, "Conversion failed for [%s]\n", inbound);
174 			strncpy(outbound, inbound, LJ_BUFFER_MAX);
175 			outbound[LJ_BUFFER_MAX-1] = '\0';
176 			return 1;
177 		}
178 		else
179 		{
180 			lj_debug(4, "Converted value [%s] to [%s]\n",
181 				inbound, outbound);
182 			return 0;
183 		}
184 #endif		/* HAVE_ICONV */
185 		strncpy(outbound, inbound, LJ_BUFFER_MAX);
186 		outbound[LJ_BUFFER_MAX-1] = '\0';
187 		return 0;
188 }
189 
190 /* hex2char
191  * Takes a html encoded (two character) string as input - without the leading %
192  * and returns a single decoded character (e.g. "41" -> 'A')
193  */
194 static char
hex2char(const char * const hex)195 hex2char(const char * const hex)
196 {
197 	char		ch = 0;
198 
199 	if (!hex[0] || !hex[1])
200 		return 0;
201 	if (hex[0] >= '0' && hex[0] <= '9')
202 		ch = hex[0] - '0';
203 	else if (hex[0] >= 'A' && hex[0] <= 'F')
204 		ch = 10 + hex[0] - 'A';
205 	else if (hex[0] >= 'a' && hex[0] <= 'f')
206 		ch = 10 + hex[0] - 'a';
207 	ch *= 16;
208 	if (hex[1] >= '0' && hex[1] <= '9')
209 		ch += hex[1] - '0';
210 	else if (hex[1] >= 'A' && hex[1] <= 'F')
211 		ch += 10 + hex[1] - 'A';
212 	else if (hex[1] >= 'a' && hex[1] <= 'f')
213 		ch += 10 + hex[1] - 'a';
214 	return ch;
215 }
216 
217 /* urldecode
218  * takes a url-encoded message as input (containing %XX or +)
219  * returns the decoded version of this message
220  * NB: the text is edited _in place_ (inpointer equals outpointer)
221  */
222 int
lj_urldecode(char * message)223 lj_urldecode(char *message)
224 {
225 	char		buffer[LJ_BUFFER_MAX];
226 	size_t		i, len = strlen(message);
227 
228 	for (i = 0; i < len; i++)
229 	{
230 		switch (message[i])
231 		{
232 		case '%':
233 			/* this potentionally does a LOT of memmoves() */
234 			message[i] = hex2char(&message[i] + 1);
235 			memmove(message + i + 1, message + i + 3, len - i);
236 			break;
237 		case '+':
238 			message[i] = ' ';
239 			break;
240 		}
241 	}
242 
243 	if (lj_chardecode(message, buffer) == 0 && strlen(buffer) <= len)
244 		strcpy(message, buffer);
245 	return 0;
246 }
247 
lj_strcopy(char * dest,const char * const src)248 char *lj_strcopy(char *dest, const char * const src)
249 {
250 	/*
251 	 * NOTE: Must make sure that the string pointer has had the memory
252 	 * malloced to it already!
253 	 */
254 	/*
255 	 * ALSO NOTE: that if src is *not* a null terminated string (at least
256 	 * "\0") the behavior of this function is not predictable
257 	 */
258 	lj_debug(4, "strcopy [%s][%d] bytes to [%p]\n",
259 		src, strlen(src) + 1, dest);
260 	strcpy(dest, src);
261 	return dest + strlen(dest);
262 }
263 
264 int
chomp(char * string)265 chomp(char *string)
266 {
267 	int             i;
268 
269 	if ((string != NULL) && (strcmp(string, ""))
270 	    && ((i = strlen(string)) > 0))
271 	{
272 		if (string[i - 1] == '\n')
273 		{
274 			string[i - 1] = '\0';
275 			return 1;
276 		}
277 	}
278 	return 0;
279 }
280 
281 int
joinstring(char * string)282 joinstring(char *string)
283 {
284 	char		*nl;
285 
286 	if (!string)
287 		return 0;
288 	for (nl = string; (nl = strchr(nl, '\n')); nl++)
289 	{
290 		if ('\n' == nl[1])
291 			nl++;
292 		else
293 			nl[0] = ' ';
294 	}
295 	return 1;
296 }
297 
298 void
lj_uniquename(char ** name)299 lj_uniquename(char **name)
300 {
301 	char		timestring[15];
302 	time_t          t;
303 
304 	time(&t);
305 	strftime(timestring, 15, "%Y%m%d%H%M%S", localtime(&t));
306 	asprintf(name, "clive.%d.%s", getuid(), timestring);
307 }
308 
309 void
lj_error(const char * const fmt,...)310 lj_error(const char * const fmt, ...)
311 {
312 	va_list	ap;
313 
314 	va_start(ap, fmt);
315 	vwarnx(fmt, ap);
316 	va_end(ap);
317 	exit(1);
318 }
319 
320 void
lj_debug(int level,const char * const msg,...)321 lj_debug(int level, const char * const msg, ...)
322 {
323 	va_list		ap;
324 
325 	if (level > debug_level)
326 		return;
327 	va_start(ap, msg);
328 	vfprintf(stderr, msg, ap);
329 	va_end(ap);
330 }
331 
332 int
lj_setauth(const lj_server * const serverinfo,lj_user * user)333 lj_setauth(const lj_server * const serverinfo, lj_user *user)
334 {
335 	char		*username, *password;
336 
337 	if (!user->username || !user->password)
338 		lj_error("You must supply a username and password to login!\n");
339 
340 	lj_urlencode(user->username, &username);
341 	if (user->auth)
342 	{
343 		free(user->auth);
344 		user->auth = NULL;
345 	}
346 
347 	switch (user->auth_method)
348 	{
349 	case pwd_plain:
350 		lj_urlencode(user->password, &password);
351 		asprintf(&user->auth, "user=%s&password=%s&ver=1",
352 			username, password);
353 		break;
354 
355 	case pwd_hash:
356 		md5_hex(user->password, &password);
357 		asprintf(&user->auth, "user=%s&hpassword=%s&ver=1",
358 			username, password);
359 		break;
360 
361 	case pwd_challenge:
362 	default:
363 	{
364 		lj_challengeinfo	challenge;
365 		char			*temp;
366 
367 		lj_getchallenge(serverinfo, user, &challenge);
368 		if (!challenge.success)
369 		{
370 			user->auth_method = pwd_hash;
371 			return lj_setauth(serverinfo, user);
372 		}
373 		md5_hex(user->password, &password);
374 		asprintf(&temp, "%s%s", challenge.challenge, password);
375 		free(password);
376 		md5_hex(temp, &password);
377 		free(temp);
378 		asprintf(&user->auth, "user=%s&auth_method=challenge"
379 			"&auth_challenge=%s&auth_response=%s&ver=1",
380 			username, challenge.challenge, password);
381 	}
382 	/* end switch */
383 	}
384 	free(username);
385 	free(password);
386 	lj_debug(2, "setup auth [%s]\n", user->auth);
387 	return 1;
388 }
389 
390 int
md5_hex(const char * value,char ** result)391 md5_hex(const char *value, char **result)
392 {
393 	*result = MD5Data((const unsigned char *)value, strlen(value), NULL);
394 
395 	lj_debug(2, "md5 hex of [%s] is [%s]\n", value, *result);
396 	return 1;
397 }
398