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