/* * Copyright (C) 2001, 2002, and 2003 Roy Keene * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * email: dact@rkeene.org */ /* * Network related functions */ #include "dact.h" #include "net.h" #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #include #ifdef HAVE_UNISTD_H #include #endif #include #ifndef NO_NETWORK #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDIO_H #include #endif #include "parse.h" #include "crc.h" #ifndef O_BINARY #define O_BINARY 0x0 #endif #ifndef S_IFSOCK #define S_IFSOCK 0140000 #endif #ifndef O_LARGEFILE #define O_LARGEFILE 0x0 #endif struct dact_url_info { char *url; int flags; mode_t mode; }; struct dact_url_info dact_urls[256]; /* Do things required for network access. */ int dact_init_net(void) { #ifdef _USE_WIN32_ WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 0), &wsaData)!=0) { return(-1); } if (wsaData.wVersion!=MAKEWORD(2, 0)) { /* Cleanup Winsock stuff */ WSACleanup(); return(-1); } #endif return(0); } /* * Create a listening port on tcp port PORT */ int createlisten(int port) { struct sockaddr_in localname; int sockFd; sockFd=socket(AF_INET,SOCK_STREAM,IPPROTO_IP); localname.sin_family=AF_INET; localname.sin_port=htons(port); localname.sin_addr.s_addr=INADDR_ANY; if (bind(sockFd,(struct sockaddr *) & localname,sizeof(localname))==-1) { perror("bind");return(-1); } if (listen(sockFd,1024)==-1) { perror("listen"); return(-1); } return(sockFd); } /* * Close that socket, yeah. */ void closeconnection(int sockfd) { shutdown(sockfd, 1); close(sockfd); } int createconnection_tcp(char *host, int port) { int sockid; struct hostent *hostinfo; struct sockaddr_in sock; if (dact_nonetwork) return(-EPERM); #ifdef HAVE_INET_ATON if (!inet_aton(host,&sock.sin_addr)) { #else #ifdef HAVE_INET_ADDR if ( (sock.sin_addr.s_addr=inet_addr(host) )==-1) { #else { #endif #endif if ((hostinfo=gethostbyname(host))==NULL) return(-EPERM); memcpy(&sock.sin_addr.s_addr,hostinfo->h_addr_list[0],hostinfo->h_length); } sock.sin_family=AF_INET; sock.sin_port=htons(port); if ((sockid=socket(AF_INET, SOCK_STREAM, 0))<0) { CHECKPOINT; return(-EIO); } if (connect(sockid, (struct sockaddr *) &sock, sizeof(sock))<0) { PERROR("connect"); CHECKPOINT; close(sockid); return(-EIO); } CHECKPOINT; return(sockid); } int open_net(const char *pathname, int flags, mode_t mode) { char scheme[5], host[512], file[1024]; char username[128], password[128]; char *read_buf, *read_buf_s=NULL; char *smallbuf, *tmpbuf; int port, fd, x, ftpfd=-1, retrmode=0; if (!parse_url(pathname,scheme,username,password,host,&port,file)) { if ((fd=createconnection_tcp(host,port))<0) return(-1); switch (elfcrc(0, scheme, strlen(scheme))) { case 457648: /* http */ if ((flags&O_WRONLY)==O_WRONLY || (flags&O_RDWR)==O_RDWR) { close(fd); return(-1); } read_buf_s=read_buf=malloc(50); write(fd, "GET ", 4); write(fd, file, strlen(file)); write(fd, " HTTP/1.0\nHost: ",16); write(fd, host, strlen(host)); write(fd, "\n", 1); if (strcmp(username, "")) { smallbuf=malloc(strlen(password)+strlen(username)+3); smallbuf[0]=0; strcat(smallbuf,username); strcat(smallbuf,":"); strcat(smallbuf,password); tmpbuf=mime64(smallbuf); write(fd, "Authorization: Basic ", 21); write(fd, tmpbuf, strlen(tmpbuf)); free(tmpbuf); free(smallbuf); write(fd, "\n", 1); } write(fd, "\n", 1); x=read(fd, read_buf, 50); strsep(&read_buf," "); if (strncmp("200 ",read_buf,4) && strncmp("302 ",read_buf,4)) { free(read_buf_s); close(fd); return(-ENOENT); } retrmode=read_buf[0]; read_buf=read_buf_s; read_buf[4]=0; while (1) { read(fd, read_buf, 1); if (read_buf[0]==read_buf[2]&&read_buf[0]=='\n') break; if (!strncmp(":noi", read_buf, 4) && retrmode=='3') { tmpbuf=smallbuf=malloc(512); read(fd, read_buf, 1); read(fd, smallbuf, 510); close(fd); return(open_net(strsep(&smallbuf,"\r\n"),flags,mode)); free(tmpbuf); } read_buf[3]=read_buf[2]; read_buf[2]=read_buf[1]; read_buf[1]=read_buf[0]; } free(read_buf_s); if (dact_urls[fd].url!=NULL) free(dact_urls[fd].url); dact_urls[fd].url=strdup(pathname); dact_urls[fd].flags=flags; dact_urls[fd].mode=mode; return(fd); break; case 28080: /* ftp */ if ((flags&O_RDWR)==O_RDWR) { close(fd); return(-1); } read_buf_s=read_buf=malloc(1024); read_buf[0]=0; while (1) { if ((x=read(fd, read_buf, 1024))<1024) { if (x<0) { free(read_buf_s); return(-EIO); } /* It's waiting for input... */ } read_buf[x]=0; while ((smallbuf=strsep(&read_buf,"\n"))!=NULL) { switch (elfcrc(0, smallbuf, 4)) { case 231456: /* 550 */ if (ftpfd!=-1) close(ftpfd); close(fd); free(read_buf_s); return(-ENOENT); break; case 230944: /* 530 */ if (ftpfd!=-1) close(ftpfd); close(fd); free(read_buf_s); return(-EIO); break; case 231504: /* 553 */ if (ftpfd!=-1) close(ftpfd); close(fd); free(read_buf_s); return(-EPERM); break; case 218400: /* 220 */ write(fd, "USER ", 5); if (strcmp(username,"")) { write(fd, username, strlen(username)); } else { write(fd, "anonymous", 9); } write(fd, "\n", 1); break; case 222768: /* 331 */ write(fd, "PASS ", 5); if (strcmp(password,"")) { write(fd, password, strlen(password)); } else { write(fd, "user@host.com", 13); } write(fd, "\n", 1); break; case 218512: /* 227 */ strsep(&smallbuf,"("); host[0]=0; for (x=0;x<4;x++) { strncat(host,strsep(&smallbuf,","),5); strcat(host,"."); } host[strlen(host)-1]=0; port=(atoi(strsep(&smallbuf,","))<<8)+atoi(strsep(&smallbuf,")\n\r ")); write(fd, "TYPE I\n", 7); break; case 217888: if ((flags&O_RDONLY)==O_RDONLY) write(fd,"RETR ",5); if ((flags&O_WRONLY)==O_WRONLY) write(fd,"STOR ",5); write(fd, file, strlen(file)); write(fd, "\n", 1); if ((ftpfd=createconnection_tcp(host,port))<0) { close(fd); return(-ENOENT); } break; case 215072: /* 150 */ if (dact_urls[ftpfd].url!=NULL) free(dact_urls[ftpfd].url); dact_urls[ftpfd].url=strdup(pathname); dact_urls[ftpfd].flags=flags; dact_urls[ftpfd].mode=mode; return(ftpfd); break; case 218656: /* 230 */ write(fd, "PASV\n", 5); break; default: #ifdef DEBUG_FTP PRINT_LINE; fprintf(stderr, "dact: Unknown cmd %i (%s)\n",elfcrc(0,smallbuf,4),smallbuf); #endif break; } } read_buf=read_buf_s; } break; } free(read_buf_s); close(fd); } else { fd=open(pathname,flags|O_BINARY|O_LARGEFILE,mode); if (dact_urls[fd].url!=NULL) free(dact_urls[fd].url); dact_urls[fd].url=strdup(pathname); dact_urls[fd].flags=flags; dact_urls[fd].mode=mode; return(fd); } return(-1); } off_t lseek_net(int filedes, off_t offset, int whence) { struct stat file_status; char tmpbuf[1024]; off_t retval, rset=0, i; size_t n; ssize_t read_val; int newfd; fstat(filedes, &file_status); if ((file_status.st_mode&S_IFSOCK)==S_IFSOCK) { if (whence!=SEEK_CUR || offset<=0) { if (whence!=SEEK_SET) return(-1); /* For now ... */ if (dact_urls[filedes].url==NULL) return(-1); if ((newfd=open_net(dact_urls[filedes].url,dact_urls[filedes].flags,dact_urls[filedes].mode))<0) return(-1); close(filedes); dup2(newfd,filedes); if (offset==0) return(0); } } else { retval=lseek(filedes, offset, whence); if (!(retval<0 && whence==SEEK_CUR && offset>0)) { return(retval); } } retval=0; for (i=0; isizeof(tmpbuf)) n=sizeof(tmpbuf); read_val=read(filedes, tmpbuf, n); if (read_val<=0) { retval=-1; break; } rset+=read_val; } retval=offset+1; return(retval); } #else #ifndef O_BINARY #define O_BINARY 0x0 #endif #ifndef O_LARGEFILE #define O_LARGEFILE 0x0 #endif int dact_init_net(void) { return(-1); } int createlisten(int port) { return(-1); } void closeconnection(int sockfd) { return; } int createconnection_tcp(char *host, int port) { return(-1); } int open_net(const char *pathname, int flags, mode_t mode) { return(open(pathname,flags|O_BINARY|O_LARGEFILE,mode)); } off_t lseek_net(int filedes, off_t offset, int whence) { char tmpbuf[1024]; off_t retval, rset=0, i; size_t n; ssize_t read_val; retval=lseek(filedes, offset, whence); if (retval<0 && whence==SEEK_CUR && offset>0) { retval=0; for (i=0; isizeof(tmpbuf)) n=sizeof(tmpbuf); read_val=read(filedes, tmpbuf, n); if (read_val<=0) { retval=-1; break; } rset+=read_val; } retval=offset+1; } return(retval); } #endif