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