1 /**
2  * @file io.c Common NDO I/O functions
3  */
4 /*
5  * Copyright 2009-2014 Nagios Core Development Team and Community Contributors
6  * Copyright 2005-2009 Ethan Galstad
7  *
8  * This file is part of NDOUtils.
9  *
10  * NDOUtils is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * NDOUtils is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with NDOUtils. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "../include/config.h"
24 #include "../include/common.h"
25 #include "../include/io.h"
26 
27 #ifdef HAVE_SSL
28 # if (defined(__sun) && defined(SOLARIS_10)) || defined(_AIX) || defined(__hpux)
29 SSL_METHOD *meth;
30 # else
31 const SSL_METHOD *meth;
32 # endif
33 SSL_CTX *ctx;
34 SSL *ssl;
35 #endif
36 
37 int use_ssl=NDO_FALSE;
38 
39 
40 /**************************************************************/
41 /****** MMAP()'ED FILE FUNCTIONS ******************************/
42 /**************************************************************/
43 
44 /* open a file read-only via mmap() */
ndo_mmap_fopen(char * filename)45 ndo_mmapfile *ndo_mmap_fopen(char *filename){
46 	ndo_mmapfile *new_mmapfile;
47 	int fd;
48 	void *mmap_buf;
49 	struct stat statbuf;
50 	int mode=O_RDONLY;
51 
52 	/* allocate memory */
53 	if((new_mmapfile=(ndo_mmapfile *)malloc(sizeof(ndo_mmapfile)))==NULL)
54 		return NULL;
55 
56 	/* open the file */
57 	if((fd=open(filename,mode))==-1){
58 		free(new_mmapfile);
59 		return NULL;
60 	        }
61 
62 	/* get file info */
63 	if((fstat(fd,&statbuf))==-1){
64 		close(fd);
65 		free(new_mmapfile);
66 		return NULL;
67 	        }
68 
69 	/* mmap() the file */
70 	if((mmap_buf=(void *)mmap(0,statbuf.st_size,PROT_READ,MAP_PRIVATE,fd,0))==MAP_FAILED){
71 		close(fd);
72 		free(new_mmapfile);
73 		return NULL;
74 	        }
75 
76 	/* populate struct info for later use */
77 	/*new_mmapfile->path=strdup(filename);*/
78 	new_mmapfile->path=NULL;
79 	new_mmapfile->fd=fd;
80 	new_mmapfile->file_size=(unsigned long)(statbuf.st_size);
81 	new_mmapfile->current_position=0L;
82 	new_mmapfile->current_line=0L;
83 	new_mmapfile->mmap_buf=mmap_buf;
84 
85 	return new_mmapfile;
86         }
87 
88 
89 /* close a file originally opened via mmap() */
ndo_mmap_fclose(ndo_mmapfile * temp_mmapfile)90 int ndo_mmap_fclose(ndo_mmapfile *temp_mmapfile){
91 
92 	if(temp_mmapfile==NULL)
93 		return NDO_ERROR;
94 
95 	/* un-mmap() the file */
96 	munmap(temp_mmapfile->mmap_buf,temp_mmapfile->file_size);
97 
98 	/* close the file */
99 	close(temp_mmapfile->fd);
100 
101 	/* free memory */
102 	if(temp_mmapfile->path!=NULL)
103 		free(temp_mmapfile->path);
104 	free(temp_mmapfile);
105 
106 	return NDO_OK;
107         }
108 
109 
110 /* gets one line of input from an mmap()'ed file */
ndo_mmap_fgets(ndo_mmapfile * temp_mmapfile)111 char *ndo_mmap_fgets(ndo_mmapfile *temp_mmapfile){
112 	char *buf=NULL;
113 	unsigned long x=0L;
114 	int len=0;
115 
116 	if(temp_mmapfile==NULL)
117 		return NULL;
118 
119 	/* we've reached the end of the file */
120 	if(temp_mmapfile->current_position>=temp_mmapfile->file_size)
121 		return NULL;
122 
123 	/* find the end of the string (or buffer) */
124 	for(x=temp_mmapfile->current_position;x<temp_mmapfile->file_size;x++){
125 		if(*((char *)(temp_mmapfile->mmap_buf)+x)=='\n'){
126 			x++;
127 			break;
128 			}
129 	        }
130 
131 	/* calculate length of line we just read */
132 	len=(int)(x-temp_mmapfile->current_position);
133 
134 	/* allocate memory for the new line */
135 	if((buf=(char *)malloc(len+1))==NULL)
136 		return NULL;
137 
138 	/* copy string to newly allocated memory and terminate the string */
139 	memcpy(buf,((char *)(temp_mmapfile->mmap_buf)+temp_mmapfile->current_position),len);
140 	buf[len]='\x0';
141 
142 	/* update the current position */
143 	temp_mmapfile->current_position=x;
144 
145 	/* increment the current line */
146 	temp_mmapfile->current_line++;
147 
148 	return buf;
149         }
150 
151 
152 
153 
154 /**************************************************************/
155 /****** SOCKET FUNCTIONS **************************************/
156 /**************************************************************/
157 
158 
159 /* opens data sink */
ndo_sink_open(char * name,int fd,int type,int port,int flags,int * nfd)160 int ndo_sink_open(char *name, int fd, int type, int port, int flags, int *nfd){
161 	struct sockaddr_un server_address_u;
162 	struct sockaddr_in server_address_i;
163 	struct hostent *hp=NULL;
164 	mode_t mode=S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
165 	int newfd=0;
166 	int rc=0;
167 
168 	/* use file */
169 	if(type==NDO_SINK_FILE){
170 		if((newfd=open(name,flags,mode))==-1)
171 			return NDO_ERROR;
172 	        }
173 
174 	/* use existing file descriptor */
175 	else if(type==NDO_SINK_FD){
176 		if(fd<0)
177 			return NDO_ERROR;
178 		else
179 			newfd=fd;
180 	        }
181 
182 	/* we are sending output to a unix domain socket */
183 	else if(type==NDO_SINK_UNIXSOCKET){
184 
185 		if(name==NULL)
186 			return NDO_ERROR;
187 
188 		/* create a socket */
189 		if(!(newfd=socket(PF_UNIX,SOCK_STREAM,0)))
190 			return NDO_ERROR;
191 
192 		/* copy the socket address/path */
193 		strncpy(server_address_u.sun_path,name,sizeof(server_address_u.sun_path));
194 		server_address_u.sun_family=AF_UNIX;
195 
196 		/* connect to the socket */
197 		if((connect(newfd,(struct sockaddr *)&server_address_u,SUN_LEN(&server_address_u)))){
198 			close(newfd);
199 			return NDO_ERROR;
200 			}
201 	        }
202 
203 	/* we are sending output to a TCP socket */
204 	else if(type==NDO_SINK_TCPSOCKET){
205 
206 		if(name==NULL)
207 			return NDO_ERROR;
208 
209 #ifdef HAVE_SSL
210 		if(use_ssl==NDO_TRUE){
211 			SSL_library_init();
212 			SSLeay_add_ssl_algorithms();
213 			meth=SSLv23_client_method();
214 			SSL_load_error_strings();
215 
216 			if((ctx=SSL_CTX_new(meth))==NULL){
217 					printf("NDOUtils: Error - could not create SSL context.\n");
218 					return NDO_ERROR;
219 			}
220 			/* ADDED 01/19/2004 */
221 			/* use only TLSv1 protocol */
222 			SSL_CTX_set_options(ctx,SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
223 	}
224 #endif
225 
226 		/* clear the address */
227 		bzero((char *)&server_address_i,sizeof(server_address_i));
228 
229 		/* try to bypass using a DNS lookup if this is just an IP address */
230 		if(!ndo_inet_aton(name,&server_address_i.sin_addr)){
231 
232 			/* else do a DNS lookup */
233 			if((hp=gethostbyname((const char *)name))==NULL)
234 				return NDO_ERROR;
235 
236 			memcpy(&server_address_i.sin_addr,hp->h_addr,hp->h_length);
237 	                }
238 
239 		/* create a socket */
240 		if(!(newfd=socket(PF_INET,SOCK_STREAM,0)))
241 			return NDO_ERROR;
242 
243 		/* copy the host/ip address and port */
244 		server_address_i.sin_family=AF_INET;
245 		server_address_i.sin_port=htons(port);
246 
247 		/* connect to the socket */
248 		if((connect(newfd,(struct sockaddr *)&server_address_i,sizeof(server_address_i)))){
249 			close(newfd);
250 			return NDO_ERROR;
251 		        }
252 
253 		#ifdef HAVE_SSL
254 		if(use_ssl==NDO_TRUE){
255 			if((ssl=SSL_new(ctx))!=NULL){
256 				SSL_CTX_set_cipher_list(ctx,"ADH");
257 				SSL_set_fd(ssl,newfd);
258 				if((rc=SSL_connect(ssl))!=1){
259 					printf("Error - Could not complete SSL handshake.\n");
260 					SSL_CTX_free(ctx);
261 					close(newfd);
262 					return NDO_ERROR;
263 				}
264 			} else {
265 				printf("NDOUtils: Error - Could not create SSL connection structure.\n");
266 				return NDO_ERROR;
267 			}
268 		}
269 #endif
270 		}
271 
272 	/* unknown sink type */
273 	else
274 		return NDO_ERROR;
275 
276 	/* save the new file descriptor */
277 	*nfd=newfd;
278 
279 	return NDO_OK;
280         }
281 
282 
283 /* writes to data sink */
ndo_sink_write(int fd,char * buf,int buflen)284 int ndo_sink_write(int fd, char *buf, int buflen){
285 	int tbytes=0;
286 	int result=0;
287 
288 	if(buf==NULL)
289 		return NDO_ERROR;
290 	if(buflen<=0)
291 		return 0;
292 
293 	while(tbytes<buflen){
294 
295 		/* try to write everything we have left */
296 #ifdef HAVE_SSL
297 		if (use_ssl == NDO_TRUE)
298 			result=SSL_write(ssl, buf+tbytes, buflen-tbytes);
299 		else
300 #endif
301 			result=write(fd, buf+tbytes, buflen-tbytes);
302 
303 
304 		/* some kind of error occurred */
305 		if(result==-1){
306 
307 			/* unless we encountered a recoverable error, bail out */
308 			if(errno!=EAGAIN && errno!=EINTR)
309 				return NDO_ERROR;
310 		        }
311 
312 		/* update the number of bytes we've written */
313 		tbytes+=result;
314 	        }
315 
316 	return tbytes;
317         }
318 
319 
320 /* writes a newline to data sink */
ndo_sink_write_newline(int fd)321 int ndo_sink_write_newline(int fd){
322 
323 	return ndo_sink_write(fd,"\n",1);
324         }
325 
326 
327 /* flushes data sink */
ndo_sink_flush(int fd)328 int ndo_sink_flush(int fd){
329 
330 	/* flush sink */
331 	fsync(fd);
332 
333 	return NDO_OK;
334         }
335 
336 
337 /* closes data sink */
ndo_sink_close(int fd)338 int ndo_sink_close(int fd){
339 
340 	/* no need to close STDOUT */
341 	if(fd==STDOUT_FILENO)
342 		return NDO_OK;
343 
344 	/* close the socket */
345 	shutdown(fd,2);
346 	close(fd);
347 
348 	return NDO_OK;
349         }
350 
351 
352 /* This code was taken from Fyodor's nmap utility, which was originally taken from
353    the GLIBC 2.0.6 libraries because Solaris doesn't contain the inet_aton() function. */
ndo_inet_aton(register const char * cp,struct in_addr * addr)354 int ndo_inet_aton(register const char *cp, struct in_addr *addr){
355 	register unsigned int val;	/* changed from u_long --david */
356 	register int base, n;
357 	register char c;
358 	unsigned int parts[4];
359 	register unsigned int *pp = parts;
360 
361 	c=*cp;
362 
363 	for(;;){
364 
365 		/*
366 		 * Collect number up to ``.''.
367 		 * Values are specified as for C:
368 		 * 0x=hex, 0=octal, isdigit=decimal.
369 		 */
370 		if (!isdigit((int)c))
371 			return (0);
372 		val=0;
373 		base=10;
374 
375 		if(c=='0'){
376 			c=*++cp;
377 			if(c=='x'||c=='X')
378 				base=16,c=*++cp;
379 			else
380 				base=8;
381 		        }
382 
383 		for(;;){
384 			if(isascii((int)c) && isdigit((int)c)){
385 				val=(val*base)+(c -'0');
386 				c=*++cp;
387 			        }
388 			else if(base==16 && isascii((int)c) && isxdigit((int)c)){
389 				val=(val<<4) | (c+10-(islower((int)c)?'a':'A'));
390 				c = *++cp;
391 			        }
392 			else
393 				break;
394 		        }
395 
396 		if(c=='.'){
397 
398 			/*
399 			 * Internet format:
400 			 *	a.b.c.d
401 			 *	a.b.c	(with c treated as 16 bits)
402 			 *	a.b	(with b treated as 24 bits)
403 			 */
404 			if(pp>=parts+3)
405 				return (0);
406 			*pp++=val;
407 			c=*++cp;
408 		        }
409 		else
410 			break;
411 	        }
412 
413 	/* Check for trailing characters */
414 	if(c!='\0' && (!isascii((int)c) || !isspace((int)c)))
415 		return (0);
416 
417 	/* Concoct the address according to the number of parts specified */
418 	n=pp-parts+1;
419 	switch(n){
420 
421 	case 0:
422 		return (0);		/* initial nondigit */
423 
424 	case 1:				/* a -- 32 bits */
425 		break;
426 
427 	case 2:				/* a.b -- 8.24 bits */
428 		if(val>0xffffff)
429 			return (0);
430 		val|=parts[0]<<24;
431 		break;
432 
433 	case 3:				/* a.b.c -- 8.8.16 bits */
434 		if(val>0xffff)
435 			return (0);
436 		val|=(parts[0]<< 24) | (parts[1]<<16);
437 		break;
438 
439 	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
440 		if(val>0xff)
441 			return (0);
442 		val|=(parts[0]<<24) | (parts[1]<<16) | (parts[2]<<8);
443 		break;
444 	        }
445 
446 	if(addr)
447 		addr->s_addr=htonl(val);
448 
449 	return (1);
450         }
451 
452 
453 /******************************************************************/
454 /************************ STRING FUNCTIONS ************************/
455 /******************************************************************/
456 
457 /* strip newline and carriage return characters from end of a string */
ndo_strip_buffer(char * buffer)458 void ndo_strip_buffer(char *buffer){
459 	register int x;
460 	register int y;
461 
462 	if(buffer==NULL || buffer[0]=='\x0')
463 		return;
464 
465 	/* strip end of string */
466 	y=(int)strlen(buffer);
467 	for(x=y-1;x>=0;x--){
468 		if(buffer[x]=='\n' || buffer[x]=='\r' || buffer[x]==13)
469 			buffer[x]='\x0';
470 		else
471 			break;
472 	        }
473 
474 	return;
475 	}
476 
477 
478 /* escape special characters in string */
ndo_escape_buffer(char * buffer)479 char *ndo_escape_buffer(char *buffer){
480 	char *newbuf;
481 	register int x=0;
482 	register int y=0;
483 	register int len=0;
484 
485 	if(buffer==NULL)
486 		return NULL;
487 
488 	/* allocate memory for escaped string */
489 	if((newbuf=(char *)malloc((strlen(buffer)*2)+1))==NULL)
490 		return NULL;
491 
492 	/* initialize string */
493 	newbuf[0]='\x0';
494 
495 	len=(int)strlen(buffer);
496 	for(x=0;x<len;x++){
497 		if(buffer[x]=='\t'){
498 			newbuf[y++]='\\';
499 			newbuf[y++]='t';
500 		        }
501 		else if(buffer[x]=='\r'){
502 			newbuf[y++]='\\';
503 			newbuf[y++]='r';
504 		        }
505 		else if(buffer[x]=='\n'){
506 			newbuf[y++]='\\';
507 			newbuf[y++]='n';
508 		        }
509 		else if(buffer[x]=='\\'){
510 			newbuf[y++]='\\';
511 			newbuf[y++]='\\';
512 		        }
513 		else
514 			newbuf[y++]=buffer[x];
515 	        }
516 
517 	/* terminate new string */
518 	newbuf[y++]='\x0';
519 
520 	return newbuf;
521         }
522 
523 
524 /* unescape special characters in string */
ndo_unescape_buffer(char * buffer)525 char *ndo_unescape_buffer(char *buffer){
526 	register int x=0;
527 	register int y=0;
528 	register int len=0;
529 
530 	if(buffer==NULL)
531 		return NULL;
532 
533 	len=(int)strlen(buffer);
534 	for(x=0;x<len;x++){
535 		if(buffer[x]=='\\'){
536 			if(buffer[x+1]=='t')
537 				buffer[y++]='\t';
538 			else if(buffer[x+1]=='r')
539 				buffer[y++]='\r';
540 			else if(buffer[x+1]=='n')
541 				buffer[y++]='\n';
542 			else if(buffer[x+1]=='\\')
543 				buffer[y++]='\\';
544 			else
545 				buffer[y++]=buffer[x+1];
546 			x++;
547 		        }
548 		else
549 			buffer[y++]=buffer[x];
550 	        }
551 
552 	/* terminate string */
553 	buffer[y++]='\x0';
554 
555 	return buffer;
556         }
557 
558 
559