1 #include "../include/config.h"
2 #include "../include/common.h"
3 
4 /*
5  * This file holds random utility functions shared by cgi's and
6  * core.
7  */
8 extern int date_format;
9 
10 /* fix the problem with strtok() skipping empty options between tokens */
my_strtok(char * buffer,char * tokens)11 char *my_strtok(char *buffer, char *tokens) {
12 	char *token_position = NULL;
13 	char *sequence_head = NULL;
14 	static char *my_strtok_buffer = NULL;
15 	static char *original_my_strtok_buffer = NULL;
16 
17 	if(buffer != NULL) {
18 		my_free(original_my_strtok_buffer);
19 		if((my_strtok_buffer = (char *)strdup(buffer)) == NULL)
20 			return NULL;
21 		original_my_strtok_buffer = my_strtok_buffer;
22 		}
23 
24 	sequence_head = my_strtok_buffer;
25 
26 	if(sequence_head[0] == '\x0')
27 		return NULL;
28 
29 	token_position = strchr(my_strtok_buffer, tokens[0]);
30 
31 	if(token_position == NULL) {
32 		my_strtok_buffer = strchr(my_strtok_buffer, '\x0');
33 		return sequence_head;
34 		}
35 
36 	token_position[0] = '\x0';
37 	my_strtok_buffer = token_position + 1;
38 
39 	return sequence_head;
40 	}
41 
42 /* fixes compiler problems under Solaris, since strsep() isn't included */
43 /* this code is taken from the glibc source */
my_strsep(char ** stringp,const char * delim)44 char *my_strsep(char **stringp, const char *delim) {
45 	char *begin, *end;
46 
47 	begin = *stringp;
48 	if(begin == NULL)
49 		return NULL;
50 
51 	/* A frequent case is when the delimiter string contains only one
52 	 * character.  Here we don't need to call the expensive `strpbrk'
53 	 * function and instead work using `strchr'.  */
54 	if(delim[0] == '\0' || delim[1] == '\0') {
55 		char ch = delim[0];
56 
57 		if(ch == '\0' || begin[0] == '\0')
58 			end = NULL;
59 		else {
60 			if(*begin == ch)
61 				end = begin;
62 			else
63 				end = strchr(begin + 1, ch);
64 			}
65 		}
66 	else {
67 		/* find the end of the token.  */
68 		end = strpbrk(begin, delim);
69 		}
70 
71 	if(end) {
72 		/* terminate the token and set *STRINGP past NUL character.  */
73 		*end++ = '\0';
74 		*stringp = end;
75 		}
76 	else
77 		/* no more delimiters; this is the last token.  */
78 		*stringp = NULL;
79 
80 	return begin;
81 	}
82 
83 /* open a file read-only via mmap() */
mmap_fopen(char * filename)84 mmapfile *mmap_fopen(char *filename) {
85 	mmapfile *new_mmapfile = NULL;
86 	int fd = 0;
87 	void *mmap_buf = NULL;
88 	struct stat statbuf;
89 	int mode = O_RDONLY;
90 	unsigned long file_size = 0L;
91 
92 	if(filename == NULL)
93 		return NULL;
94 
95 	/* allocate memory */
96 	if((new_mmapfile = (mmapfile *) malloc(sizeof(mmapfile))) == NULL)
97 		return NULL;
98 
99 	/* open the file */
100 	if((fd = open(filename, mode)) == -1) {
101 		my_free(new_mmapfile);
102 		return NULL;
103 		}
104 
105 	/* get file info */
106 	if((fstat(fd, &statbuf)) == -1) {
107 		close(fd);
108 		my_free(new_mmapfile);
109 		return NULL;
110 		}
111 
112 	/* get file size */
113 	file_size = (unsigned long)statbuf.st_size;
114 
115 	/* only mmap() if we have a file greater than 0 bytes */
116 	if(file_size > 0) {
117 
118 		/* mmap() the file - allocate one extra byte for processing zero-byte files */
119 		if((mmap_buf =
120 		            (void *)mmap(0, file_size, PROT_READ, MAP_PRIVATE, fd,
121 		                         0)) == MAP_FAILED) {
122 			close(fd);
123 			my_free(new_mmapfile);
124 			return NULL;
125 			}
126 		}
127 	else
128 		mmap_buf = NULL;
129 
130 	/* populate struct info for later use */
131 	new_mmapfile->path = (char *)strdup(filename);
132 	new_mmapfile->fd = fd;
133 	new_mmapfile->file_size = (unsigned long)file_size;
134 	new_mmapfile->current_position = 0L;
135 	new_mmapfile->current_line = 0L;
136 	new_mmapfile->mmap_buf = mmap_buf;
137 
138 	return new_mmapfile;
139 	}
140 
141 /* close a file originally opened via mmap() */
mmap_fclose(mmapfile * temp_mmapfile)142 int mmap_fclose(mmapfile * temp_mmapfile) {
143 
144 	if(temp_mmapfile == NULL)
145 		return ERROR;
146 
147 	/* un-mmap() the file */
148 	if(temp_mmapfile->file_size > 0L)
149 		munmap(temp_mmapfile->mmap_buf, temp_mmapfile->file_size);
150 
151 	/* close the file */
152 	close(temp_mmapfile->fd);
153 
154 	/* free memory */
155 	my_free(temp_mmapfile->path);
156 	my_free(temp_mmapfile);
157 
158 	return OK;
159 	}
160 
161 /* gets one line of input from an mmap()'ed file */
mmap_fgets(mmapfile * temp_mmapfile)162 char *mmap_fgets(mmapfile * temp_mmapfile) {
163 	char *buf = NULL;
164 	unsigned long x = 0L;
165 	int len = 0;
166 
167 	if(temp_mmapfile == NULL)
168 		return NULL;
169 
170 	/* size of file is 0 bytes */
171 	if(temp_mmapfile->file_size == 0L)
172 		return NULL;
173 
174 	/* we've reached the end of the file */
175 	if(temp_mmapfile->current_position >= temp_mmapfile->file_size)
176 		return NULL;
177 
178 	/* find the end of the string (or buffer) */
179 	for(x = temp_mmapfile->current_position; x < temp_mmapfile->file_size;
180 	        x++) {
181 		if(*((char *)(temp_mmapfile->mmap_buf) + x) == '\n') {
182 			x++;
183 			break;
184 			}
185 		}
186 
187 	/* calculate length of line we just read */
188 	len = (int)(x - temp_mmapfile->current_position);
189 
190 	/* allocate memory for the new line */
191 	if((buf = (char *)malloc(len + 1)) == NULL)
192 		return NULL;
193 
194 	/* copy string to newly allocated memory and terminate the string */
195 	memcpy(buf,
196 	       ((char *)(temp_mmapfile->mmap_buf) +
197 	        temp_mmapfile->current_position), len);
198 	buf[len] = '\x0';
199 
200 	/* update the current position */
201 	temp_mmapfile->current_position = x;
202 
203 	/* increment the current line */
204 	temp_mmapfile->current_line++;
205 
206 	return buf;
207 	}
208 
209 /* gets one line of input from an mmap()'ed file (may be contained on more than one line in the source file) */
mmap_fgets_multiline(mmapfile * temp_mmapfile)210 char *mmap_fgets_multiline(mmapfile * temp_mmapfile) {
211 	char *buf = NULL;
212 	char *tempbuf = NULL;
213 	char *stripped = NULL;
214 	int len = 0;
215 	int len2 = 0;
216 	int end = 0;
217 
218 	if(temp_mmapfile == NULL)
219 		return NULL;
220 
221 	while(1) {
222 
223 		my_free(tempbuf);
224 
225 		if((tempbuf = mmap_fgets(temp_mmapfile)) == NULL)
226 			break;
227 
228 		if(buf == NULL) {
229 			len = strlen(tempbuf);
230 			if((buf = (char *)malloc(len + 1)) == NULL)
231 				break;
232 			memcpy(buf, tempbuf, len);
233 			buf[len] = '\x0';
234 			}
235 		else {
236 			/* strip leading white space from continuation lines */
237 			stripped = tempbuf;
238 			while(*stripped == ' ' || *stripped == '\t')
239 				stripped++;
240 			len = strlen(stripped);
241 			len2 = strlen(buf);
242 			if((buf =
243 			            (char *)realloc(buf, len + len2 + 1)) == NULL)
244 				break;
245 			strcat(buf, stripped);
246 			len += len2;
247 			buf[len] = '\x0';
248 			}
249 
250 		if(len == 0)
251 			break;
252 
253 		/* handle Windows/DOS CR/LF */
254 		if(len >= 2 && buf[len - 2] == '\r')
255 			end = len - 3;
256 		/* normal Unix LF */
257 		else if(len >= 1 && buf[len - 1] == '\n')
258 			end = len - 2;
259 		else
260 			end = len - 1;
261 
262 		/* two backslashes found. unescape first backslash first and break */
263 		if(end >= 1 && buf[end - 1] == '\\' && buf[end] == '\\') {
264 			buf[end] = '\n';
265 			buf[end + 1] = '\x0';
266 			break;
267 			}
268 
269 		/* one backslash found. continue reading the next line */
270 		else if(end > 0 && buf[end] == '\\')
271 			buf[end] = '\x0';
272 
273 		/* no continuation marker was found, so break */
274 		else
275 			break;
276 		}
277 
278 	my_free(tempbuf);
279 
280 	return buf;
281 	}
282 
283 /* strip newline, carriage return, and tab characters from beginning and end of a string */
strip(char * buffer)284 void strip(char *buffer) {
285 	register int x, z;
286 	int len;
287 
288 	if(buffer == NULL || buffer[0] == '\x0')
289 		return;
290 
291 	/* strip end of string */
292 	len = (int)strlen(buffer);
293 	for(x = len - 1; x >= 0; x--) {
294 		switch(buffer[x]) {
295 			case ' ':
296 			case '\n':
297 			case '\r':
298 			case '\t':
299 				buffer[x] = '\x0';
300 				continue;
301 			}
302 		break;
303 		}
304 
305 	/* if we stripped all of it, just return */
306 	if(!x)
307 		return;
308 
309 	/* save last position for later... */
310 	z = x;
311 
312 	/* strip beginning of string (by shifting) */
313 	/* NOTE: this is very expensive to do, so avoid it whenever possible */
314 	for(x = 0;; x++) {
315 		switch(buffer[x]) {
316 			case ' ':
317 			case '\n':
318 			case '\r':
319 			case '\t':
320 				continue;
321 			}
322 		break;
323 		}
324 
325 	if(x > 0 && z > 0) {
326 		/* new length of the string after we stripped the end */
327 		len = z + 1;
328 
329 		/* shift chars towards beginning of string to remove leading whitespace */
330 		for(z = x; z < len; z++)
331 			buffer[z - x] = buffer[z];
332 		buffer[len - x] = '\x0';
333 		}
334 	}
335 
336 /**************************************************
337  *************** HASH FUNCTIONS *******************
338  **************************************************/
339 /* dual hash function */
hashfunc(const char * name1,const char * name2,int hashslots)340 int hashfunc(const char *name1, const char *name2, int hashslots) {
341 	unsigned int i, result;
342 
343 	result = 0;
344 
345 	if(name1)
346 		for(i = 0; i < strlen(name1); i++)
347 			result += name1[i];
348 
349 	if(name2)
350 		for(i = 0; i < strlen(name2); i++)
351 			result += name2[i];
352 
353 	result = result % hashslots;
354 
355 	return result;
356 	}
357 
358 /* dual hash data comparison */
compare_hashdata(const char * val1a,const char * val1b,const char * val2a,const char * val2b)359 int compare_hashdata(const char *val1a, const char *val1b, const char *val2a,
360                      const char *val2b) {
361 	int result = 0;
362 
363 	/* NOTE: If hash calculation changes, update the compare_strings() function! */
364 
365 	/* check first name */
366 	if(val1a == NULL && val2a == NULL)
367 		result = 0;
368 	else if(val1a == NULL)
369 		result = 1;
370 	else if(val2a == NULL)
371 		result = -1;
372 	else
373 		result = strcmp(val1a, val2a);
374 
375 	/* check second name if necessary */
376 	if(result == 0) {
377 		if(val1b == NULL && val2b == NULL)
378 			result = 0;
379 		else if(val1b == NULL)
380 			result = 1;
381 		else if(val2b == NULL)
382 			result = -1;
383 		else
384 			result = strcmp(val1b, val2b);
385 		}
386 
387 	return result;
388 	}
389 /*
390  * given a date/time in time_t format, produce a corresponding
391  * date/time string, including timezone
392  */
get_datetime_string(time_t * raw_time,char * buffer,int buffer_length,int type)393 void get_datetime_string(time_t * raw_time, char *buffer, int buffer_length,
394                          int type) {
395 	time_t t;
396 	struct tm *tm_ptr, tm_s;
397 	int hour;
398 	int minute;
399 	int second;
400 	int month;
401 	int day;
402 	int year;
403 	char *weekdays[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
404 	char *months[12] = {
405 		"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept",
406 		"Oct", "Nov", "Dec"
407 		};
408 	char *tzone = "";
409 
410 	if(raw_time == NULL)
411 		time(&t);
412 	else
413 		t = *raw_time;
414 
415 	if(type == HTTP_DATE_TIME)
416 		tm_ptr = gmtime_r(&t, &tm_s);
417 	else
418 		tm_ptr = localtime_r(&t, &tm_s);
419 
420 	hour = tm_ptr->tm_hour;
421 	minute = tm_ptr->tm_min;
422 	second = tm_ptr->tm_sec;
423 	month = tm_ptr->tm_mon + 1;
424 	day = tm_ptr->tm_mday;
425 	year = tm_ptr->tm_year + 1900;
426 
427 #ifdef HAVE_TM_ZONE
428 	tzone = (char *)(tm_ptr->tm_zone);
429 #else
430 	tzone = (tm_ptr->tm_isdst) ? tzname[1] : tzname[0];
431 #endif
432 
433 	/* ctime() style date/time */
434 	if(type == LONG_DATE_TIME)
435 		snprintf(buffer, buffer_length, "%s %s %d %02d:%02d:%02d %s %d",
436 		         weekdays[tm_ptr->tm_wday], months[tm_ptr->tm_mon], day,
437 		         hour, minute, second, tzone, year);
438 
439 	/* short date/time */
440 	else if(type == SHORT_DATE_TIME) {
441 		if(date_format == DATE_FORMAT_EURO)
442 			snprintf(buffer, buffer_length,
443 			         "%02d-%02d-%04d %02d:%02d:%02d", day, month,
444 			         year, hour, minute, second);
445 		else if(date_format == DATE_FORMAT_ISO8601
446 		        || date_format == DATE_FORMAT_STRICT_ISO8601)
447 			snprintf(buffer, buffer_length,
448 			         "%04d-%02d-%02d%c%02d:%02d:%02d", year, month,
449 			         day,
450 			         (date_format ==
451 			          DATE_FORMAT_STRICT_ISO8601) ? 'T' : ' ', hour,
452 			         minute, second);
453 		else
454 			snprintf(buffer, buffer_length,
455 			         "%02d-%02d-%04d %02d:%02d:%02d", month, day,
456 			         year, hour, minute, second);
457 		}
458 
459 	/* short date */
460 	else if(type == SHORT_DATE) {
461 		if(date_format == DATE_FORMAT_EURO)
462 			snprintf(buffer, buffer_length, "%02d-%02d-%04d", day,
463 			         month, year);
464 		else if(date_format == DATE_FORMAT_ISO8601
465 		        || date_format == DATE_FORMAT_STRICT_ISO8601)
466 			snprintf(buffer, buffer_length, "%04d-%02d-%02d", year,
467 			         month, day);
468 		else
469 			snprintf(buffer, buffer_length, "%02d-%02d-%04d", month,
470 			         day, year);
471 		}
472 
473 	/* expiration date/time for HTTP headers */
474 	else if(type == HTTP_DATE_TIME)
475 		snprintf(buffer, buffer_length,
476 		         "%s, %02d %s %d %02d:%02d:%02d GMT",
477 		         weekdays[tm_ptr->tm_wday], day, months[tm_ptr->tm_mon],
478 		         year, hour, minute, second);
479 
480 	/* short time */
481 	else
482 		snprintf(buffer, buffer_length, "%02d:%02d:%02d", hour, minute,
483 		         second);
484 
485 	buffer[buffer_length - 1] = '\x0';
486 	}
487 
488 /* get days, hours, minutes, and seconds from a raw time_t format or total seconds */
get_time_breakdown(unsigned long raw_time,int * days,int * hours,int * minutes,int * seconds)489 void get_time_breakdown(unsigned long raw_time, int *days, int *hours,
490                         int *minutes, int *seconds) {
491 	unsigned long temp_time;
492 	int temp_days;
493 	int temp_hours;
494 	int temp_minutes;
495 	int temp_seconds;
496 
497 	temp_time = raw_time;
498 
499 	temp_days = temp_time / 86400;
500 	temp_time -= (temp_days * 86400);
501 	temp_hours = temp_time / 3600;
502 	temp_time -= (temp_hours * 3600);
503 	temp_minutes = temp_time / 60;
504 	temp_time -= (temp_minutes * 60);
505 	temp_seconds = (int)temp_time;
506 
507 	*days = temp_days;
508 	*hours = temp_hours;
509 	*minutes = temp_minutes;
510 	*seconds = temp_seconds;
511 	}
512