/* * Copyright (c) 2000-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ /* OpenFWTK project - TIS fwtk legacy API * (c) ArkanoiD 2000,2002 */ #include "firewall.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "auth.h" #include "fwfunc.h" #ifndef F_ULOCK #define F_ULOCK 0 #define F_LOCK 1 #define F_TLOCK 2 #endif #ifndef INADDR_NONE #define INADDR_NONE (in_addr_t) -1 #endif static char* moduleId ATTR_UNUSED = "$Id: sysapi.c,v 1.15 2007/09/24 23:05:07 arkenoi Exp $"; extern char *ip2name(); extern int isalldigits(); extern size_t strlcpy(char*,const char*,size_t); extern size_t strlcat(char*,const char*,size_t); extern int proxy_nodns; int str_to_port(char *portstr) { struct servent *sp; if (isalldigits(portstr)) return(atoi(portstr)); if ( (sp = getservbyname(portstr,"tcp")) ) return(ntohs(sp->s_port)); syslog(LLEV,"fwtkcfgerr: cannot decode %.100s as port",portstr); exit(1); } int mapgid(char *gnam) { struct group *gp; if (isalldigits(gnam)) return(atoi(gnam)); if ( (gp = getgrnam(gnam)) ) return(gp->gr_gid); return(-1); } int mapuid(char *user) { struct passwd *pwd; if (isalldigits(user)) return(atoi(user)); if ( (pwd = getpwnam(user)) ) return(pwd->pw_uid); return(-1); } /* * Return peer name and address or unix/unix if socket is AF_UNIX * This code relies on some assumptions valid for all today's unix systems: * 1) sizeof(sockaddr_un) > sizeof(sockaddr_in), since it stores quite long * sun_path[UNIX_PATH_MAX]. * 2) sockaddr_un.sun_family, sockaddr_in.sin_family all have the same offset * (zero to sockaddr struct beginning) * Those are checked externally by structchk.c program before library build. */ int peername(int fd,char *lname,char *sname,int z) { char optbuf[256]; socklen_t optsize; char *optp; char logbuf[MAX_STR]; socklen_t addrlen; struct sockaddr_un sua; struct sockaddr *sa = (struct sockaddr *) &sua; struct sockaddr_in *sia = (struct sockaddr_in *)&sua; char *x; int protoval; socklen_t protolen; char tbuf[1500]; addrlen = sizeof(struct sockaddr_un); memset(sname,0,z); memset(lname,0,z); protolen = sizeof(int); if (getsockopt(fd,SOL_SOCKET,SO_TYPE,(char *)&protoval,&protolen)) { syslog(LLEV,"fwtksyserr: cannot get protocol id, %s", strerror(errno)); return(1); } switch (protoval) { case SOCK_STREAM: if (getpeername(fd,(struct sockaddr *)sa,&addrlen)<0) { if (errno!=ENOTCONN) syslog(LLEV,"fwtksyserr: getpeername failed: %s", strerror(errno)); return(1); } break; case SOCK_DGRAM: if (recvfrom(fd,tbuf,sizeof(tbuf),MSG_PEEK, (struct sockaddr *)sa,&addrlen) < 0) { syslog(LLEV,"fwtksyserr: UDP socket error %s", strerror(errno)); return(1); } if (connect(fd,(struct sockaddr *)sa,sizeof(sa))) { syslog(LLEV,"fwtksyserr: UDP socket connect error %s", strerror(errno)); return(1); } break; default: syslog(LLEV,"fwtksyserr: unknown protocol %d",protoval); return(1); } if(sia->sin_family == AF_INET) { strlcat(sname,inet_ntoa(sia->sin_addr),z); if (!getsockopt(fd,IPPROTO_IP,IP_OPTIONS,optbuf,&optsize) && optsize) { memset(logbuf,0,sizeof(logbuf)); for (optp = optbuf; optsize > 0; optp++, optsize--) snprintf(logbuf,sizeof(logbuf),"%s %2.2x",logbuf,*optp); syslog(LLEV,"securityalert: Connection received using IP options (ignored):%.100s",logbuf); if (setsockopt(fd,IPPROTO_IP,IP_OPTIONS,NULL,0)) { syslog(LLEV,"fwtksyserr: setsockopt IP_OPTIONS NULL: %s", strerror(errno)); strlcpy(lname,"unknown",z); return(0); } } if (proxy_nodns) { strlcpy(lname,"unknown",z); return(0); } if (strlen(x=ip2name(sia->sin_addr)) >= z) { syslog(LLEV,"securityalert: %.512s/%.20s host name buffer overrun",x,sname); strlcpy(lname,"unknown",z); return(0); } lname[0] = '\0'; strlcat(lname,x,z); } else if(sua.sun_family == AF_UNIX) { strlcat(sname, "unix", z); strlcat(lname, "unix", z); } return(0); } int conn_server(char *srv,int portnum,int priv,char *rbuf) { struct hostent *hp; struct sockaddr_in sa; unsigned char *p; int lport = IPPORT_RESERVED - 1; int s; bzero(&sa,sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(portnum); /* used to have port selection routine here but checking current rresvport implementations shows that this functions does that pretty well */ if (priv) s = rresvport(&lport); else s = socket(AF_INET, SOCK_STREAM, 0); if (s<0) { syslog(LLEV,"fwtksyserr: socket: %.50s",strerror(errno)); if (rbuf) snprintf(rbuf,MAX_STR,"socket: %.50s",strerror(errno)); return(-2); } for (p = (unsigned char *) srv; *p ; p++) { if ((*p != '.') && !isdigit(*p)) break; } if (!*p) { if ((sa.sin_addr.s_addr = inet_addr(srv)) == INADDR_NONE) { if (rbuf) strlcpy(rbuf,"hostname unparsable",MAX_STR); return(-1); } if (connect(s,(struct sockaddr *)&sa,sizeof(sa)) <0) { if (rbuf) snprintf(rbuf,MAX_STR,"connect: %.50s",strerror(errno)); return(-3); } return(s); } else { if((hp = gethostbyname(srv)) == (struct hostent *)0) { if (rbuf) strlcpy(rbuf,"hostname unknown",MAX_STR); return(-1); } if(hp->h_length != sizeof(sa.sin_addr.s_addr)) { syslog(LLEV,"securityalert: invalid host address length (%d) hostname %.512s",hp->h_length, srv); strlcpy(rbuf, "hostname invalid",MAX_STR); return (-1); } for ( ; *(hp->h_addr_list) ; hp->h_addr_list++ ) { sa.sin_addr.s_addr = *(uint32_t*)*(hp->h_addr_list); if (connect(s,(struct sockaddr *)&sa,sizeof(sa)) >=0) return(s); } if (rbuf) snprintf(rbuf,MAX_STR,"connect: %.50s",strerror(errno)); return(-3); } } int conn_server_unixsock(char *srv, char *rbuf) { int s; struct sockaddr_un sa; char srv_path[sizeof(sa.sun_path)]; char* sock_path; s = socket(PF_UNIX, SOCK_STREAM, 0); if (s<0) { syslog(LLEV,"fwtksyserr: socket: %.50s",strerror(errno)); if (rbuf) snprintf(rbuf,MAX_STR,"socket: %.50s",strerror(errno)); return(-2); } strncpy(srv_path, srv, sizeof(srv_path)); strtrm(srv_path); /* Trim spaces and possible "unix:" prefix */ sock_path = (!strncasecmp(srv_path, "unix:", strlen("unix:")) ? srv_path + strlen("unix:") : srv_path); strlcpy(sa.sun_path, sock_path, sizeof(sa.sun_path)); sa.sun_family = AF_UNIX; if (connect(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) { if (rbuf) snprintf(rbuf,MAX_STR,"connect: %.50s",strerror(errno)); return(-3); } return(s); } char* maphostname(char *name) { struct hostent *hp; char *p; for (p = name; *p ; p++) if ((*p != '.') && !isdigit(*p)) break; if(!*p) return(name); if(!(hp = gethostbyname(name))) return(name); if (hp->h_length != sizeof(struct in_addr)) { syslog(LLEV,"securityalert: invalid host address length (%d) hostname %.200s", hp->h_length, name); return ("invalid"); } return(inet_ntoa(*(struct in_addr *)(hp->h_addr))); } int lock_fd(int f) { return(lockf(f,F_LOCK,0)); } int lockun_fd(int f) { return(lockf(f,F_ULOCK,0)); } int locktest_fd(int f) { return(lockf(f,F_TLOCK,0)); }