/* VTun - Virtual Tunnel over TCP/IP network. Copyright (C) 1998-2008 Maxim Krasnyansky VTun has been derived from VPPP package by Maxim Krasnyansky. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ /* * $Id: lib.c,v 1.9.2.4 2013/07/07 20:21:20 mtbishop Exp $ */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "vtun.h" #include "linkfd.h" #include "lib.h" volatile sig_atomic_t __io_canceled = 0; #ifndef HAVE_SETPROC_TITLE /* Functions to manipulate with program title */ extern char **environ; static char *title_start; /* start of the proc title space */ static char *title_end; /* end of the proc title space */ static int title_size; void init_title(int argc,char *argv[], char *envp[], char *name) { int i; /* * Move the environment so settitle can use the space at * the top of memory. */ for (i = 0; envp[i]; i++); environ = (char **) malloc(sizeof (char *) * (i + 1)); for(i = 0; envp[i]; i++) environ[i] = strdup(envp[i]); environ[i] = NULL; /* * Save start and extent of argv for set_title. */ title_start = argv[0]; /* * Determine how much space we can use for set_title. * Use all contiguous argv and envp pointers starting at argv[0] */ for(i=0; i title_size - 1) buf[title_size - 1] = '\0'; strcat(title_start, buf); } #endif /* HAVE_SETPROC_TITLE */ /* * Print padded messages. * Used by 'auth' function to force all messages * to be the same len. */ int print_p(int fd,const char *fmt, ...) { char buf[VTUN_MESG_SIZE]; va_list ap; memset(buf,0,sizeof(buf)); /* print the argument string */ va_start(ap, fmt); if (vsnprintf(buf,sizeof(buf)-1, fmt, ap) >= VTUN_MESG_SIZE) abort(); va_end(ap); return write_n(fd, buf, sizeof(buf)); } /* Read N bytes with timeout */ int readn_t(int fd, void *buf, size_t count, time_t timeout) { fd_set fdset; struct timeval tv; tv.tv_usec=0; tv.tv_sec=timeout; FD_ZERO(&fdset); FD_SET(fd,&fdset); if( select(fd+1,&fdset,NULL,NULL,&tv) <= 0) return -1; return read_n(fd, buf, count); } /* * Substitutes opt in place off '%X'. * Returns new string. */ static char * subst_opt(char *str, struct vtun_sopt *opt) { register int slen, olen, sp, np; register char *optr, *nstr, *tmp; char buf[10]; if( !str ) return NULL; slen = strlen(str) + 1; if( !(nstr = malloc(slen)) ) return str; sp = np = 0; while( str[sp] ){ switch( str[sp] ){ case '%': optr = NULL; /* Check supported opt */ switch( str[sp+1] ){ case '%': case 'd': optr=opt->dev; break; case 'A': optr=opt->laddr; break; case 'P': sprintf(buf,"%d",opt->lport); optr=buf; break; case 'a': optr=opt->raddr; break; case 'p': sprintf(buf,"%d",opt->rport); optr=buf; break; case 'h': optr=opt->host; break; default: sp++; continue; } if( optr ){ /* Opt found substitute */ olen = strlen(optr); slen = slen - 2 + olen; if( !(tmp = realloc(nstr, slen)) ){ free(nstr); return str; } nstr = tmp; memcpy(nstr + np, optr, olen); np += olen; } sp += 2; continue; case '\\': nstr[np++] = str[sp++]; if( !nstr[sp] ) continue; /* fall through */ default: nstr[np++] = str[sp++]; break; } } nstr[np] = '\0'; return nstr; } /* * Split arguments string. * ' ' - group arguments * Modifies original string. */ static void split_args(char *str, char **argv) { register int i = 0; int mode = 0; while( str && *str ){ switch( *str ){ case ' ': if( mode == 1 ){ *str = '\0'; mode = 0; i++; } break; case '\'': if( !mode ){ argv[i] = str+1; mode = 2; } else { memmove(argv[i]+1, argv[i], str - argv[i]); argv[i]++; if( mode == 1 ) mode = 2; else mode = 1; } break; case '\\': if( mode ){ memmove(argv[i]+1, argv[i], str - argv[i]); argv[i]++; } if( !*(++str) ) continue; /*Fall through */ default: if( !mode ){ argv[i] = str; mode = 1; } break; } str++; } if( mode == 1 || mode == 2) i++; argv[i]=NULL; } #ifdef HAVE_WORKING_FORK int run_cmd(void *d, void *opt) { struct vtun_cmd *cmd = d; char *argv[50], *args; int pid, st; switch( (pid=fork()) ){ case 0: break; case -1: vtun_syslog(LOG_ERR,"Couldn't fork()"); return 0; default: if( cmd->flags & VTUN_CMD_WAIT ){ /* Wait for termination */ if( waitpid(pid,&st,0) > 0 && (WIFEXITED(st) && WEXITSTATUS(st)) ) vtun_syslog(LOG_INFO,"Command [%s %.20s] error %d", cmd->prog ? cmd->prog : "sh", cmd->args ? cmd->args : "", WEXITSTATUS(st) ); } if( cmd->flags & VTUN_CMD_DELAY ){ struct timespec tm = { VTUN_DELAY_SEC, 0 }; /* Small delay hack to sleep after pppd start. * Until I have no good solution for solving * PPP + route problem */ nanosleep(&tm, NULL); } return 0; } args = subst_opt(cmd->args, opt); if( !cmd->prog ){ /* Run using shell */ cmd->prog = "/bin/sh"; argv[0] = "sh"; argv[1] = "-c"; argv[2] = args; argv[3] = NULL; } else { argv[0] = cmd->prog; split_args(args, argv + 1); } execv(cmd->prog, argv); vtun_syslog(LOG_ERR,"Couldn't exec program %s", cmd->prog); exit(1); } #endif void free_sopt( struct vtun_sopt *opt ) { if( opt->dev ){ free(opt->dev); opt->dev = NULL; } if( opt->laddr ){ free(opt->laddr); opt->laddr = NULL; } if( opt->raddr ){ free(opt->raddr); opt->raddr = NULL; } } void vtun_syslog (int priority, char *format, ...) { static volatile sig_atomic_t in_syslog= 0; char buf[255]; va_list ap; if(! in_syslog) { in_syslog = 1; va_start(ap, format); vsnprintf(buf, sizeof(buf)-1, format, ap); syslog(priority, "%s", buf); closelog(); va_end(ap); in_syslog = 0; } }