/* * sockets - open a socket connection and read/write to nntp server * * Copyright (C) 1992/93/94 Stephen Hebditch . * All rights reserved. TQM Communications, BCM Box 225, London, WC1N 3XX. * * See README for more information and disclaimers * * Obtain the current time from the remote server in standard unix time * format for use with the next NEWNEWS. If the client is unable to * connect to the time server, then local time is used instead. * * $Id: sockets.c,v 1.9 1995/01/10 13:09:21 root Exp $ * * $Log: sockets.c,v $ * Revision 1.9 1995/01/10 13:09:21 root * Moved includes from slurp.h. * Added additional parameter to tcp_open() to specify port number * if required. * Moved in do_authinfo() and do_mode_reader() from slurp.c. * General tidying-up. * * Revision 1.7 1993/06/23 10:15:37 root * Replaced bzero/bcopy definitions with ANSI memcpy and memset. * Duplicate fd before using fdopen separately on each fd for read * and write, fixing long-standing stdio memory problems. * * Revision 1.6 1993/04/22 18:25:16 root * If NOBUFFOUT defined then turn off stdio buffering for the * output stream to the server to get round problem with SVR3s. * * Revision 1.5 1993/03/01 18:00:18 root * Use ferror to detect erros, not return code. * * Revision 1.4 1993/02/14 16:22:42 root * No longer have get_server return a return code. Makes this module * no longer compatible with nntp 1.6 client library, but there ya go... * Changed error detection in put_server for no other reason than to * be consistent with elsewhere. * * Revision 1.3 1992/12/15 * Removed unnecessary close() in close_server. * Syslog log level for connected message changed to LOG_INFO. * * Revision 1.1 1992/12/04 * Print line before it is sent to server when debugging is on. * * Revision 1.0 1992/11/29 * Adapted from nntpxfer-e code. * Incorporate code to set up a tcp connection, plus cleaned up the * existing code. */ #include "conf.h" /* POSIX headers */ #undef _POSIX_SOURCE #include #include #include #include #include #include #include #include #include #ifndef NOUNISTD #include #endif /* IP headers */ #include #include #include #include /* Local headers */ #include "nntp.h" #include "slurp.h" #include "syslog.h" /* Fixes */ #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif /* File-scope variables */ static struct sockaddr_in serv_addr; static struct servent serv_info; static struct hostent host_info; static jmp_buf env_alrm; static FILE *server_rd_fp; static FILE *server_wr_fp; /* * tcp_open - Open a tcp connection to 'host' for service 'service', * returning a file descriptor for the socket. */ int tcp_open (const char *host, const char *service, const int portno) { int on = 1; int sockfd; struct hostent *hp; struct servent *sp; unsigned long inaddr; (void) memset (&serv_addr, 0, sizeof (serv_addr)); serv_addr.sin_family = AF_INET; /* Get service information if required*/ if (portno == 0) { if ((sp = getservbyname (service, "tcp")) == NULL) { log_ret ("tcp_open: unknown service %s/tcp", service); return (-1); } serv_info = *sp; serv_addr.sin_port = sp -> s_port; } else { serv_addr.sin_port = htons (portno); } /* Try to convert host name as dotted decimal */ if ((inaddr = inet_addr (host)) != INADDR_NONE) { (void) memcpy (&serv_addr.sin_addr, &inaddr, sizeof (inaddr)); host_info.h_name = NULL; } /* If that failed, then look up the host name */ else { if ((hp = gethostbyname (host)) == NULL) { log_ret ("tcp_open: host name error: %s", host); return (-1); } host_info = *hp; (void) memcpy (&serv_addr.sin_addr, hp -> h_addr, hp -> h_length); } if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { log_ret ("tcp_open: can't create TCP socket"); return (-1); } if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) { log_ret ("tcp_open: can't connect to server %s", host); (void) close (sockfd); return (-1); } if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on)) < 0) log_ret ("tcp_open: can't set KEEPALIVE on socket"); return (sockfd); } /* * server_init - Open a connection to the NNTP server. Returns -1 if an * error occurs, otherwise the server's initial response code. */ int server_init (const char *hostname, const int portno) { char line [NNTP_STRLEN]; int server_rd_fd; int server_wr_fd; /* First try and make the connection */ if ((server_rd_fd = tcp_open (hostname, "nntp", portno)) < 0) return (-1); server_wr_fd = dup (server_rd_fd); /* Now fdopen to enable buffering of data */ if ((server_rd_fp = fdopen (server_rd_fd, "r")) == NULL) { log_ret ("server_init: can't fdopen socket for reading"); return (-1); } if ((server_wr_fp = fdopen (server_wr_fd, "w")) == NULL) { log_ret ("server_init: can't fdopen socket for writing"); return (-1); } /* Inform everyone that we're there */ #ifdef SYSLOG if (!debug_flag) syslog (LOG_INFO, "Connected to nntp server at %s", hostname); else #endif (void) fprintf (stderr, "Connected to nntp server at %s\n", hostname); /* Get the greeting herald */ get_server (line, sizeof (line)); if (debug_flag) (void) fprintf (stderr, "-> %s\n", line); /* Return the banner code */ return (atoi (line)); } /* * close_server - Close down the NNTP server connection, sending a * QUIT message to the server then closing the socket. */ void close_server (void) { char line [NNTP_STRLEN]; if (debug_flag) (void) fprintf (stderr, "<- QUIT\n"); put_server ("QUIT"); get_server (line, sizeof (line)); if (debug_flag) (void) fprintf (stderr, "-> %s\n", line); (void) fclose (server_rd_fp); (void) fclose (server_wr_fp); } /* * sig_alrm - Signal handler for socket read timeout */ static void sig_alrm (int signo) { longjmp (env_alrm, 1); } /* * get_server - Read a line up to CRLF from the socket into a buffer. * Will timeout after TIMEOUT seconds if nothing is read from the socket. */ void get_server (char *line, const int size) { int esave; char *pos; /* Set up an alarm to handle socket timeout */ if (setjmp (env_alrm)) { (void) alarm (0); /* Reset alarm clock */ (void) signal (SIGALRM, SIG_DFL); errno = EPIPE; log_sys ("get_server: read error on server socket"); } (void) signal (SIGALRM, sig_alrm); (void) alarm (TIMEOUT); /* Read line */ (void) fgets (line, size, server_rd_fp); /* Reset the alarm */ esave = errno; (void) alarm (0); (void) signal (SIGALRM, SIG_DFL); errno = esave; /* Report any error */ if (ferror (server_rd_fp)) log_sys ("get_server: read error on server socket"); /* Kill the CRLF */ if ((pos = strchr (line, '\r')) != NULL) *pos = '\0'; if ((pos = strchr (line, '\n')) != NULL) *pos = '\0'; } /* * put_server - write a line from a string to a socket */ void put_server (const char *line) { (void) fprintf (server_wr_fp, "%s\r\n", line); if (ferror (server_wr_fp)) log_sys ("put_server: write error on server socket"); (void) fflush (server_wr_fp); } /* * do_authinfo - Check in the authinfo username and password with the * server. */ void do_authinfo (const char *username, const char *password) { char line [NNTP_STRLEN]; /* Send the username to the server */ (void) sprintf (line, "AUTHINFO USER %s", username); if (debug_flag) (void) fprintf (stderr, "<- %s\n", line); put_server (line); /* Get the response and check it's okay */ get_server (line, sizeof (line)); if (debug_flag) (void) fprintf (stderr, "-> %s\n", line); if (atoi (line) != NEED_AUTHDATA) { log_msg ("do_authinfo: NNTP protocol error: got '%s'", line); exit (4); } /* Send the password to the server */ (void) sprintf (line, "AUTHINFO PASS %s", password); if (debug_flag) (void) fprintf (stderr, "<- %s\n", line); put_server (line); /* Get the response and check it's okay */ get_server (line, sizeof (line)); if (debug_flag) (void) fprintf (stderr, "-> %s\n", line); if (atoi (line) != OK_AUTH) { log_msg ("do_authinfo: NNTP protocol error: got '%s'", line); exit (4); } } /* * do_mode_reader - Send mode reader command to INN to switch to nnrpd * so we can do a NEWNEWS. */ void do_mode_reader (void) { char line [NNTP_STRLEN]; /* Send the command to the server */ if (debug_flag) (void) fprintf (stderr, "<- MODE READER\n"); put_server ("MODE READER"); /* Get the response and check it's okay */ get_server (line, sizeof (line)); if (debug_flag) (void) fprintf (stderr, "-> %s\n", line); switch (atoi (line)) { case OK_CANPOST : case OK_NOPOST : break; default : log_msg ("do_mode_reader: NNTP protocol error: got '%s'", line); exit (4); } } /* END-OF-FILE */