Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

NewsCache.cc File Reference

#include "config.h"
#include <crypt.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <limits.h>
#include <socket++/sockstream.h>
#include <pwd.h>
#include <iostream>
#include <algorithm>
#include <map>
#include "NServer.h"
#include "Newsgroup.h"
#include "util.h"
#include "setugid.h"
#include "Config.h"
#include "Logger.h"

Go to the source code of this file.

Classes

struct  nnrp_command_t
class  NNRPCommandMap
class  ClientData
class  print_list_active
class  print_list_active_times
class  active_filter_group
class  active_filter_group_time
class  active_filter_time

Defines

#define CONF_MultiClient
#define SOCKLEN_TYPE   size_t
#define REJECT_SEQUENCE   "502"
#define PASS_NEEDED_SEQUENCE   "381"
#define OK_SEQUENCE   "281"
#define INCORRECT_ORDER_SEQUENCE   "482"
#define DD2INT(x)   ((x)[0]-'0')*10+((x)[1]-'0')
#define USAGE

Typedefs

typedef nnrp_command_t nnrp_command_t

Enumerations

enum  { AUTH_REQUIRED, AUTH_OK, AUTH_FAILED, AUTH_NOT_REQUIRED }

Functions

int ns_authinfo (ClientData *clt, int argc, char *argv[])
int ns_article (ClientData *clt, int argc, char *argv[])
int ns_stat (ClientData *clt, int argc, char *argv[])
int ns_date (ClientData *clt, int argc, char *argv[])
int ns_group (ClientData *clt, int argc, char *argv[])
int ns_help (ClientData *clt, int argc, char *argv[])
int ns_lastnext (ClientData *clt, int argc, char *argv[])
int ns_list (ClientData *clt, int argc, char *argv[])
int ns_listgroup (ClientData *clt, int argc, char *argv[])
int ns_mode (ClientData *clt, int argc, char *argv[])
int ns_newgroups (ClientData *clt, int argc, char *argv[])
int ns_post (ClientData *clt, int argc, char *argv[])
int ns_quit (ClientData *clt, int argc, char *argv[])
int ns_xmotd (ClientData *clt, int argc, char *argv[])
int ns_xover (ClientData *clt, int argc, char *argv[])
int ns_xdebug (ClientData *clt, int argc, char *argv[])
void set_client_command_table (ClientData &clt)
char ** seekfile (const char *filename, const char *username)
int auto_cryptcheck (const char *key, const char *pass)
int check_auth_unix (ClientData *clt)
int check_auth_file (ClientData *clt)
int check_authentication (ClientData *clt)
int fillHostStruct (struct sockaddr_in *addr, char *pHost)
GroupInfoselectgroup (ClientData *clt, const char *group)
void nsh_particle (ClientData *clt, char *cmnd, int nbr, Article *a)
void nnrpd (int fd)
void nntpd ()
void sigchld (int num)
void catchsigalarm (int num)
void catchsighup (int num)
void catchsignal (int num)
int main (int argc, char **argv)

Variables

char * ConfigurationOptions []
int clientTimeoutReached = 0
Logger slog
const char * cmnd
char config_file [MAXPATHLEN]
Config Cfg
int Xsignal
int nntp_connections


Define Documentation

#define CONF_MultiClient
 

Definition at line 130 of file NewsCache.cc.

#define DD2INT  )     ((x)[0]-'0')*10+((x)[1]-'0')
 

Definition at line 1527 of file NewsCache.cc.

Referenced by ns_newgroups().

#define INCORRECT_ORDER_SEQUENCE   "482"
 

Definition at line 900 of file NewsCache.cc.

Referenced by ns_authinfo().

#define OK_SEQUENCE   "281"
 

Definition at line 899 of file NewsCache.cc.

Referenced by ns_authinfo().

#define PASS_NEEDED_SEQUENCE   "381"
 

Definition at line 898 of file NewsCache.cc.

Referenced by ns_authinfo().

#define REJECT_SEQUENCE   "502"
 

Definition at line 897 of file NewsCache.cc.

Referenced by ns_authinfo().

#define SOCKLEN_TYPE   size_t
 

Definition at line 138 of file NewsCache.cc.

Referenced by nntpd().

#define USAGE
 

Value:

"       -h, --help\n"\
"              Show summary of options.\n"\
"\n"\
"       -v, --version\n"\
"              Show version of program.\n"\
"\n"\
"       -f --fqdn\n"\
"              Print what newscache thinks is the fully qualified domain  name.\n"\
"\n"\
"       -c --configuration config-file\n"\
"\n"\
"       -i --inetd\n"\
"              newscache is used with inetd and read from stdin.\n"\
"\n"\
"       -d --debug\n"\
"              Do not detach.\n"\
"\n"\
"       -p --print-parameter\n"\
"              Print current parameter settings.\n"\
"\n"\
"       -o --configurtion-options\n"\
"              Print all options specified in the configure phase.\n"

Definition at line 2493 of file NewsCache.cc.

Referenced by main().


Typedef Documentation

typedef struct nnrp_command_t nnrp_command_t
 


Enumeration Type Documentation

anonymous enum
 

Enumeration values:
AUTH_REQUIRED 
AUTH_OK 
AUTH_FAILED 
AUTH_NOT_REQUIRED 

Definition at line 304 of file NewsCache.cc.

00304      {
00305         AUTH_REQUIRED,
00306         AUTH_OK,
00307         AUTH_FAILED,
00308         AUTH_NOT_REQUIRED
00309 };


Function Documentation

int auto_cryptcheck const char *  key,
const char *  pass
 

Definition at line 443 of file NewsCache.cc.

References md5crypt().

Referenced by check_auth_file(), and check_auth_unix().

00444 {
00445 #ifdef MD5_AUTO
00446         if (strlen(pass) == 24 && pass[23] == '=' && pass[22] == '=') {
00447                 // looks like an MD5 hash
00448 #endif
00449 #ifdef MD5_CRYPT
00450                 return strcmp(pass, (const char *) md5crypt(key));
00451 #endif
00452 #ifdef MD5_AUTO
00453         } else {
00454 #endif
00455                 return strcmp(pass, (const char *) crypt(key, pass));
00456 #ifdef MD5_AUTO
00457         }
00458 #endif                          /*MD5_AUTO */
00459         return 0;
00460 }

void catchsigalarm int  num  ) 
 

Definition at line 2444 of file NewsCache.cc.

References catchsigalarm(), clientTimeoutReached, Logger::p(), and slog.

Referenced by catchsigalarm(), and main().

02445 {
02446         slog.p(Logger::Debug) << "receiving signal SIGALRM: " << num << "\n";
02447         clientTimeoutReached=1;
02448 #ifdef HAVE_SIGACTION
02449         /* Reinstall the signal handler */
02450         struct sigaction action;
02451         action.sa_handler = catchsigalarm;
02452         sigemptyset(&action.sa_mask);
02453         action.sa_flags = 0;
02454         sigaction(num, &action, NULL);
02455 #else
02456         signal(num, catchsigalarm);
02457 #endif
02458 }

void catchsighup int  num  ) 
 

Definition at line 2460 of file NewsCache.cc.

References catchsighup(), Cfg, config_file, Config::init(), Logger::p(), Config::read(), and slog.

Referenced by catchsighup(), and main().

02461 {
02462         slog.p(Logger::Debug) << "receiving signal SIGHUP: " << num << "\n";
02463         Cfg.init();
02464         Cfg.read(config_file);
02465 #ifdef HAVE_SIGACTION
02466         /* Reinstall the signal handler */
02467         struct sigaction action;
02468         action.sa_handler = catchsighup;
02469         sigemptyset(&action.sa_mask);
02470         action.sa_flags = 0;
02471         sigaction(num, &action, NULL);
02472 #else
02473         signal(num, catchsighup);
02474 #endif
02475 }

void catchsignal int  num  ) 
 

Definition at line 2477 of file NewsCache.cc.

References catchsignal(), Logger::p(), slog, and Xsignal.

Referenced by catchsignal(), and main().

02478 {
02479         slog.p(Logger::Debug) << "receiving signal: " << num << "\n";
02480         Xsignal = num;
02481 #ifdef HAVE_SIGACTION
02482         /* Reinstall the signal handler */
02483         struct sigaction action;
02484         action.sa_handler = catchsignal;
02485         sigemptyset(&action.sa_mask);
02486         action.sa_flags = 0;
02487         sigaction(num, &action, NULL);
02488 #else
02489         signal(num, catchsignal);
02490 #endif
02491 }

int check_auth_file ClientData clt  ) 
 

Definition at line 508 of file NewsCache.cc.

References ClientData::access_entry, Authentication::appendField(), ClientData::auth_pass, ClientData::auth_user, AccessEntry::authentication, auto_cryptcheck(), Authentication::getField(), NewsgroupFilter::getRulelist(), AccessEntry::list, AccessEntry::modifyAccessFlags(), Logger::p(), AccessEntry::postTo, AccessEntry::read, seekfile(), Authentication::set(), slog, and Authentication::typeEqual().

Referenced by check_authentication().

00509 {
00510         AccessEntry *access_entry = clt->access_entry;
00511         string type("file:");
00512 
00513         if (access_entry->authentication.typeEqual (type))
00514                 return -1;
00515 
00516         string authfile = access_entry->authentication.getField(1);
00517         char **authv = seekfile(authfile.c_str(), clt->auth_user);
00518         int authc = 0;
00519         int passf=-1;
00520 
00521         if (!authv)
00522                 return -1;
00523 
00524         while (authv[authc])
00525                 authc++;
00526         if (authc < 3)
00527                 return -1;
00528 
00529 
00530 #ifdef PLAIN_TEXT_PASSWORDS
00531         passf=strcmp(clt->auth_pass, authv[1]);
00532 #endif
00533         if (passf)
00534                 passf=auto_cryptcheck(clt->auth_pass, authv[1]);
00535         if (passf)
00536                 return -1;
00537 
00538         // Now we build a authentication string like the 
00539         // unix:::: authentication string and set authentication
00540         // Herbert Straub
00541         access_entry->authentication.set (type+authfile);
00542         for (authc=2; authv[authc]; authc++) {
00543                 access_entry->authentication.appendField(authv[authc]);
00544         }
00545         access_entry->list |= NewsgroupFilter(
00546                         (access_entry->authentication.getField(2))
00547                         .c_str());
00548         access_entry->read |= NewsgroupFilter(
00549                         (access_entry->authentication.getField(3))
00550                         .c_str());
00551         access_entry->postTo |= NewsgroupFilter(
00552                         (access_entry->authentication.getField(4)).
00553                         c_str());
00554         access_entry->modifyAccessFlags (access_entry->authentication.
00555                         getField(5));
00556         slog.p(Logger::Debug) << "check_auth_file::NewsgroupFilter set to: "
00557                 << access_entry->list.getRulelist() << ":"
00558                 << access_entry->read.getRulelist() << ":"
00559                 << access_entry->postTo.getRulelist() << "\n";
00560         
00561         return 0;
00562 }

int check_auth_unix ClientData clt  ) 
 

Definition at line 462 of file NewsCache.cc.

References ClientData::access_entry, ClientData::auth_pass, ClientData::auth_user, AccessEntry::authentication, auto_cryptcheck(), Authentication::getField(), NewsgroupFilter::getRulelist(), AccessEntry::list, AccessEntry::modifyAccessFlags(), Logger::p(), AccessEntry::postTo, AccessEntry::read, slog, and Authentication::typeEqual().

Referenced by check_authentication().

00463 {
00464         AccessEntry *access_entry = clt->access_entry;
00465         string type("unix:");
00466 
00467         if (access_entry->authentication.typeEqual (type))
00468                 return -1;
00469 
00470         const char *pass;
00471         struct passwd *pw = NULL;
00472         pw = getpwnam(clt->auth_user);
00473         if (!pw || !(pw->pw_name) || !(pw->pw_passwd)
00474             || !(pw->pw_passwd[0]))
00475                 return -1;
00476         pass = pw->pw_passwd;
00477 #ifdef SHADOW_PASSWORD
00478         if ((pass[0] == 'x') && (pass[1] == '\0')) {
00479                 struct spwd *spw = NULL;
00480                 spw = getspnam(pw->pw_name);
00481                 if (!(spw) || !(spw->sp_namp) || !(spw->sp_pwdp))
00482                         return -1;
00483                 pass = spw->sp_pwdp;
00484         }
00485 #endif
00486         if (auto_cryptcheck(clt->auth_pass, pass))
00487                 return -1;
00488 
00489         access_entry->list |= NewsgroupFilter(
00490                         (access_entry->authentication.getField(1))
00491                         .c_str());
00492         access_entry->read |= NewsgroupFilter(
00493                         (access_entry->authentication.getField(2))
00494                         .c_str());
00495         access_entry->postTo |= NewsgroupFilter(
00496                         (access_entry->authentication.getField(3)).
00497                         c_str());
00498         access_entry->modifyAccessFlags (access_entry->authentication.
00499                         getField(4));
00500         slog.p(Logger::Debug) << "check_auth_unix::NewsgroupFilter set to: "
00501                 << access_entry->list.getRulelist() << ":"
00502                 << access_entry->read.getRulelist() << ":"
00503                 << access_entry->postTo.getRulelist() << "\n";
00504 
00505         return 0;
00506 }

int check_authentication ClientData clt  ) 
 

Definition at line 722 of file NewsCache.cc.

References ClientData::access_entry, AccessEntry::authentication, check_auth_file(), check_auth_unix(), and Authentication::getType().

Referenced by ns_authinfo().

00723 {
00724         AccessEntry *access_entry = clt->access_entry;
00725 
00726         if (access_entry->authentication.getType() == "none") {
00727                 return -1;
00728         }
00729 
00730         if (!strncmp((access_entry->authentication.getType()).c_str()
00731                                 , "unix", 4)) {
00732                 return check_auth_unix (clt);
00733         } else
00734             if (!strncmp((access_entry->authentication.getType()).c_str(),
00735                                     "file", 4))
00736         {
00737                 return check_auth_file (clt);
00738         }
00739 #ifdef PAM_AUTH
00740         else if (!strncmp
00741                  ((access_entry->authentication.getType()).c_str(),
00742                   "pam+file", 8)) {
00743                 return check_auth_pam_file (clt);
00744         }
00745         else if (!strncmp
00746                  ((access_entry->authentication.getType()).c_str(),
00747                   "pam", 3)) {
00748                 return check_auth_pam (clt);
00749         }
00750 #endif                          /* #ifndef PAM_AUTH */
00751         // auth_{deny,none} is handled in nnrpd()
00752         return -1;
00753 }

int fillHostStruct struct sockaddr_in *  addr,
char *  pHost
 

Definition at line 757 of file NewsCache.cc.

References Logger::Error, Logger::p(), and slog.

Referenced by nntpd().

00758 {
00759         char fname[] = "getHost";
00760         char *p;
00761         struct servent *cport;
00762         struct hostent *host;
00763         int portFlg = 0;
00764 
00765         addr->sin_family = AF_INET;
00766 
00767         if ((p = strchr(pHost, ':')) != NULL) {
00768                 portFlg = 1;
00769                 *p = '\0';
00770         }
00771 
00772         if (strcmp(pHost, "DEFAULT") == 0) {
00773                 addr->sin_addr.s_addr = INADDR_ANY;
00774         } else if ((addr->sin_addr.s_addr = inet_addr(pHost)) ==
00775                    INADDR_NONE) {
00776                 if ((host =
00777                      gethostbyname(pHost)) == NULL | host->h_addrtype !=
00778                     AF_INET) {
00779                         if (portFlg)
00780                                 *p = ':';
00781                         slog.
00782                             p(Logger::
00783                               Error) << fname << ": gethostbyname (" <<
00784                             pHost << ") error: " << strerror(errno) <<
00785                             "\n";
00786                         return -1;
00787                 } else {
00788                         if (host->h_addr_list[0]) {
00789                                 memcpy(&addr->sin_addr.s_addr,
00790                                        host->h_addr_list[0],
00791                                        host->h_length);
00792                         } else {
00793                                 if (portFlg)
00794                                         *p = ':';
00795                                 slog.
00796                                     p(Logger::
00797                                       Error) << fname <<
00798                                     ":host->h_addr_list[0] of " << pHost <<
00799                                     "not valid\n";
00800                                 return -1;
00801                         }
00802                 }
00803         }
00804         if (portFlg)
00805                 *p = ':';
00806 
00807         if (portFlg && isdigit(*(p + 1))) {
00808                 addr->sin_port = htons(atoi(p + 1));
00809         } else
00810             if ((cport =
00811                  getservbyname((portFlg) ? (p + 1) : ("nntp"),
00812                                "tcp")) == NULL) {
00813 
00814                 slog.p(Logger::Error) << fname << ": getservbyname ("
00815                     << ((portFlg) ? ((const char *) (p + 1))
00816                         : ((const char *) "nntp")) << "/tcp error \n";
00817                 return -1;
00818         } else {
00819                 addr->sin_port = cport->s_port;
00820         }
00821 
00822         return 1;
00823 }

int main int  argc,
char **  argv
 

Definition at line 2517 of file NewsCache.cc.

References catchsigalarm(), catchsighup(), catchsignal(), Cfg, cmnd, config_file, ConfigurationOptions, Logger::Error, getfqdn(), Config::Groupname, Config::Hostname, Config::LogDirectory, nnrpd(), nntp_hostname, nntpd(), Logger::open(), Logger::p(), PACKAGE, Config::printParameters(), Config::read(), Config::ServerType, setugid(), sigchld(), slog, USAGE, Config::Username, and Xsignal.

02518 {
02519 #ifndef WITH_SYSLOG
02520         char logfile[MAXPATHLEN];
02521         time_t t;
02522         pid_t p;
02523 #endif
02524         int opt_config = 0, opt_inetd = 0, opt_debug = 0, opt_print_para = 0;
02525         int opt_config_options = 0;
02526         int aerr = 0, c;
02527 
02528         sprintf(config_file, "%s/newscache.conf", SYSCONFDIR);
02529 
02530         cmnd = argv[0];
02531         while (1) {
02532                 int option_index = 0;
02533                 static struct option long_options[] = {
02534                         {"version", 0, 0, 'v'},
02535                         {"fqdn", 0, 0, 'f'},
02536                         {"help", 0, 0, 'h'},
02537                         {"configuration", 1, 0, 'c'},
02538                         {"inetd", 0, 0, 'i'},
02539                         {"debug", 0, 0, 'd'},
02540                         {"print-parameter", 0, 0, 'p'},
02541                         {"configuration-options", 0, 0, 'o'},
02542                         {0, 0, 0, 0}
02543                 };
02544 
02545                 c = getopt_long (argc, argv, "vfhc:idpo", long_options,
02546                                 &option_index);
02547                 if (c == -1) 
02548                         break;
02549 
02550                 switch (c) {
02551                         case 'v':
02552                                 cout << PACKAGE << " " VERSION << endl;
02553                                 exit (0);
02554                                 break;
02555                         
02556                         case 'f':
02557                                 cout << getfqdn () << endl;
02558                                 exit (0);
02559                                 break;
02560                         
02561                         case 'h':
02562                                 cout << "Usage: " << cmnd << " [options]\n"
02563                                         << USAGE;
02564                                 exit (0);
02565                                 break;
02566                         
02567                         case 'c':
02568                                 strcpy (config_file, optarg);
02569                                 ++opt_config;
02570                                 break;
02571 
02572                         case 'i':
02573                                 ++opt_inetd;
02574                                 break;
02575 
02576                         case 'd':
02577                                 ++opt_debug;
02578                                 break;
02579                         case 'p':
02580                                 ++opt_print_para;
02581                                 break;
02582                         case 'o':
02583                                 ++opt_config_options;
02584                                 break;
02585                         default:
02586                                 aerr = 1;
02587                                 break;
02588                 }
02589         }
02590 
02591         if (aerr || optind != argc) {
02592                 cerr << "Usage: " << cmnd << " [options]\n" << USAGE;
02593                 exit(1);
02594         }
02595 
02596         try {
02597                 Cfg.read(config_file);
02598                 strcpy(nntp_hostname, Cfg.Hostname);
02599         }
02600         catch(IOError & io) {
02601                 cerr << "unexpected EOF in " << config_file << "\n";
02602                 exit(2);
02603         }
02604         catch(SyntaxError & se) {
02605                 cerr << se._errtext << "\n";
02606                 exit(2);
02607         }
02608 
02609         if (opt_print_para) {
02610                 cout << "# This output is generated with newscache -p" << endl;
02611                 Cfg.printParameters (&cout);
02612                 exit (0);
02613         }
02614 
02615         if (opt_config_options) {
02616                 for (int i=0; ConfigurationOptions[i] != NULL; i++) {
02617                         cout << ConfigurationOptions[i] << " ";
02618                 }
02619                 cout << endl;
02620                 exit (0);
02621         }
02622 
02623 #ifdef WITH_SYSLOG
02624         slog.open(PACKAGE, LOG_NDELAY | LOG_PID, LOG_NEWS);
02625 #else
02626         sprintf (logfile, "%s/newscache.log", Cfg.LogDirectory);
02627         slog.open (logfile);
02628 #endif
02629 
02630         // signal handling
02631         Xsignal = -1;
02632 
02633 #ifdef HAVE_SIGACTION
02634         struct sigaction action;
02635 
02636         // alarm - client timeout signal
02637         action.sa_handler = catchsigalarm;
02638         sigemptyset(&action.sa_mask);
02639         action.sa_flags = 0;
02640         sigaction(SIGALRM, &action, NULL);
02641 
02642         // reread config file
02643         action.sa_handler = catchsighup;
02644         sigemptyset(&action.sa_mask);
02645         action.sa_flags = 0;
02646         sigaction(SIGHUP, &action, NULL);
02647 
02648         // signals indicating to terminate NewsCache
02649         action.sa_handler = catchsignal;
02650         sigaction(SIGINT, &action, NULL);
02651         sigaction(SIGPIPE, &action, NULL);
02652         sigaction(SIGTERM, &action, NULL);
02653 
02654         // ignored signals
02655         action.sa_handler = SIG_IGN;
02656         sigaction(SIGUSR1, &action, NULL);
02657         sigaction(SIGUSR2, &action, NULL);
02658 
02659         // clean zombies
02660         action.sa_handler = sigchld;
02661         sigaction(SIGCHLD, &action, NULL);
02662 #else
02663         signal(SIGALRM, catchsigalarm);
02664         signal(SIGHUP, catchsighup);
02665         signal(SIGINT, catchsignal);
02666         signal(SIGPIPE, catchsignal);
02667         signal(SIGTERM, catchsignal);
02668 
02669         signal(SIGUSR1, SIG_IGN);
02670         signal(SIGUSR2, SIG_IGN);
02671 
02672         signal(SIGCHLD, sigchld);
02673 #endif
02674 
02675         if (Cfg.ServerType == Config::inetd)
02676                 opt_inetd = 1;
02677 
02678         if (opt_inetd) {
02679                 if (getuid() == CONF_UIDROOT)
02680                         setugid(Cfg.Username, Cfg.Groupname);
02681                 nnrpd(-1);
02682         } else {
02683                 if (opt_debug == 0) {
02684                         switch (fork()) {
02685                         case -1:
02686                                 cerr << "cannot fork\n";
02687                                 slog.p(Logger::Error) << "cannot fork\n";
02688                                 break;
02689                         case 0:
02690                                 if (setsid() == -1) {
02691                                         cerr << "setsid failed\n";
02692                                         slog.
02693                                             p(Logger::
02694                                               Error) << "setsid failed\n";
02695                                         exit(1);
02696                                 }
02697                                 close(STDIN_FILENO);
02698                                 close(STDOUT_FILENO);
02699                                 close(STDERR_FILENO);
02700                                 break;
02701                         default:
02702                                 return 0;
02703                         }
02704                 }
02705                 nntpd();
02706         }
02707 
02708         return 0;
02709 }

void nnrpd int  fd  ) 
 

Definition at line 1869 of file NewsCache.cc.

References ClientData::access_entry, AccessEntry::access_flags, ClientData::auth_failures, ClientData::auth_max_failures, AUTH_NOT_REQUIRED, AUTH_REQUIRED, ClientData::auth_state, ClientData::auth_user, AccessEntry::authentication, Cfg, ClientData::ci, AccessList::client(), ClientData::client_command_map, ClientData::client_logname, ClientData::client_name, Config::ClientTimeout, clientTimeoutReached, Config::clnts, ClientData::co, Authentication::getNrOfFields(), Authentication::getType(), ClientData::groupname, AccessEntry::hostname, Config::LogStyle, Config::NiceServer, nntp_posting_host, Logger::p(), PACKAGE, Logger::print(), set_client_command_table(), CServer::setttl(), slog, ClientData::sock, ClientData::socklen, Config::SpoolDirectory, ClientData::srvr, Config::srvrs, ClientData::stat_articles, ClientData::stat_artingrp, ClientData::stat_groups, Config::ttl_desc, Config::ttl_list, and Xsignal.

Referenced by main(), and nntpd().

01870 {
01871         struct hostent *he;
01872         ClientData clt;
01873         char req[1024], oreq[1024], *rp;
01874         char *argv[256];
01875         int argc;
01876         const char *cmd;
01877         map < string, nnrp_command_t * >::iterator cmdp, end =
01878             nnrp_commands.end();
01879         int errc = 0;
01880         sockbuf *psock_buff = NULL;
01881         iosockstream *psock_stream = NULL;
01882         int nice;
01883 
01884         /* set nice value for master server */
01885 #ifdef HAVE_SETPRIORITY
01886         errno = 0;
01887         nice = Cfg.NiceServer;
01888         nice += getpriority(PRIO_PROCESS, 0);
01889         if (nice == -1 && errno != 0) {
01890                 slog.
01891                     p(Logger::
01892                       Error) << "getpriority failed: " << strerror(errno)
01893                     << "\n";
01894         } else {
01895                 if (setpriority(PRIO_PROCESS, 0, nice) == -1)
01896                         slog.
01897                             p(Logger::
01898                               Error) << "setpriority failed: " <<
01899                             strerror(errno) << "\n";
01900         }
01901 #endif
01902 
01903         if (fd >= 0) {
01904                 // FIXME: check NULL Pointer and throw exception
01905                 psock_buff = new sockbuf(fd);
01906                 psock_buff->setname ("nntp client socket");
01907                 psock_stream = new iosockstream(psock_buff);
01908                 psock_buff->recvtimeout(-1);
01909                 psock_buff->sendtimeout(-1);
01910                 psock_stream->unsetf(ios::skipws);
01911                 clt.co = psock_stream;
01912                 clt.ci = psock_stream;
01913 
01914                 // get network address and name of client
01915                 clt.socklen = sizeof(clt.sock);
01916                 if (getpeername
01917                     (fd, (struct sockaddr *) &clt.sock,
01918                      &clt.socklen) < 0) {
01919                         // Cannot get socket --- connection from stdin?
01920                         sprintf(clt.client_name, "fd#%d", fd);
01921                         clt.client_logname = clt.client_name;
01922                 } else {
01923                         // get the name of the client and store it in clt.client_name.
01924                         // if the client does not have a name, use the ip-address instead
01925                         // store it in nntp_posting_host as used by libnserver
01926                         he = gethostbyaddr((const char *)
01927                                            &(clt.sock.sin_addr),
01928                                            sizeof(clt.sock.sin_addr),
01929                                            AF_INET);
01930                         if (he) {
01931                                 strncpy(clt.client_name, he->h_name,
01932                                         sizeof(clt.client_name));
01933                                 clt.client_name[sizeof(clt.client_name) -
01934                                                 1] = '\0';
01935                         } else {
01936                                 strncpy(clt.client_name,
01937                                         inet_ntoa(clt.sock.sin_addr),
01938                                         sizeof(clt.client_name));
01939                                 clt.client_name[sizeof(clt.client_name) -
01940                                                 1] = '\0';
01941                         }
01942                         strcpy(nntp_posting_host, clt.client_name);
01943 
01944                         // add the client's name to its logging name (clt.client_logname),
01945                         // if names should be logged
01946                         if (Cfg.LogStyle & Config::LogName) {
01947                                 clt.client_logname = clt.client_name;
01948                         }
01949 
01950                         if (Cfg.LogStyle & Config::LogAddr) {
01951                                 if (clt.client_logname.length() > 0)
01952                                         clt.client_logname += " [";
01953                                 else
01954                                         clt.client_logname += '[';
01955                                 clt.client_logname +=
01956                                     inet_ntoa(clt.sock.sin_addr);
01957                                 clt.client_logname += ']';
01958                         }
01959                         // check whether the client is allowed access according to
01960                         // libwrap
01961 #ifdef HAVE_LIBWRAP
01962                         // Check the hosts_access configuration; emulate INN error message
01963                         if (!hosts_ctl(PACKAGE,
01964                                        clt.client_name,
01965                                        inet_ntoa(clt.sock.sin_addr),
01966                                        STRING_UNKNOWN)) {
01967                                 slog.p(Logger::Notice) << clt.
01968                                     client_logname << " denied - hosts.allow\n";
01969                                 (*clt.
01970                                  co) <<
01971                                "502 You have no permission to talk.  Goodbye.\n";
01972                                 clt.co->flush ();
01973                                 return;
01974                         }
01975 #endif
01976                 }
01977         } else {
01978                 cin.unsetf(ios::skipws);
01979                 clt.ci = &cin;
01980                 clt.co = &cout;
01981                 strcpy(clt.client_name, "stdin");
01982                 clt.client_logname = clt.client_name;
01983                 fd = 0;
01984         }
01985 
01986 #ifdef NO_STREAM_BUFFERING
01987         {
01988                 streambuf *b;
01989                 b = clt.ci->rdbuf();
01990                 if (b)
01991                         b->setbuf(0, 0);
01992                 b = clt.co->rdbuf();
01993                 if (b)
01994                         b->setbuf(0, 0);
01995         }
01996 #endif
01997 
01998         // check whether the client is allowed access according to
01999         // our own access configuration
02000         clt.access_entry =
02001             Cfg.clnts.client(clt.client_name, clt.sock.sin_addr);
02002         if (!clt.access_entry || !clt.access_entry->access_flags) {
02003 //   nnrpd_deny:
02004                 slog.p(Logger::Notice) << clt.
02005                     client_logname << " denied\n";
02006                 (*clt.
02007                  co) << "502 You have no permission to talk.  Goodbye.\n";
02008                 clt.co->flush();
02009                 return;
02010         } else {
02011                 slog.p(Logger::Debug) << "nnrpd: access_entry name matched: "
02012                         << clt.access_entry->hostname << "\n";
02013         }
02014 
02015         slog.p(Logger::Notice) << clt.client_logname << " connect\n";
02016 
02017         if (clt.access_entry->authentication.getType() != "none") {
02018                 clt.auth_state = AUTH_REQUIRED;
02019         }
02020         if (clt.access_entry->authentication.getType() == "unix" &&
02021             clt.access_entry->authentication.getNrOfFields() > 1) {
02022                 // authentication optional, not required
02023                 clt.auth_state = AUTH_NOT_REQUIRED;
02024         }
02025         if (clt.access_entry->authentication.getType() == "file") {
02026                 // authentication optional, not required
02027                 clt.auth_state = AUTH_NOT_REQUIRED;
02028         }
02029         if (clt.access_entry->authentication.getType() == "pam") {
02030                 // authentication optional, not required
02031                 clt.auth_state = AUTH_NOT_REQUIRED;
02032         }
02033         if (clt.access_entry->authentication.getType() == "pam+file") {
02034                 // authentication optional, not required
02035                 clt.auth_state = AUTH_NOT_REQUIRED;
02036         }
02037 
02038         // Set client command table, can be changed after successfully
02039         // authentication!
02040         set_client_command_table (clt);
02041 
02042         try {
02043                 clt.srvr = new CServer(Cfg.SpoolDirectory, &(Cfg.srvrs));
02044                 clt.srvr->setttl(Cfg.ttl_list, Cfg.ttl_desc);
02045         }
02046         catch(SystemError & se) {
02047                 slog.
02048                     p(Logger::
02049                       Alert) << "CServer failed, check permissions\n";
02050                 se.print();
02051                 (*clt.
02052                  co) << "400 " PACKAGE " " VERSION
02053                ", service not available\r\n";
02054                 exit(1);
02055         }
02056 
02057         (*clt.
02058          co) << "200 " PACKAGE " " VERSION ", accepting NNRP commands\r\n";
02059         do {
02060                 flush(*clt.co);
02061 
02062                 alarm (Cfg.ClientTimeout);
02063                 clt.ci->getline(req, sizeof(req), '\n');
02064                 alarm (0);
02065                 if (clientTimeoutReached) {
02066                         (*clt.co) << "400 " PACKAGE " " VERSION ", service timed out!\r\n";
02067                         slog.p(Logger::Notice) << clt.client_logname << " ClientTimeout reached\n";
02068                         goto client_exit;
02069                 }
02070                 if (Xsignal >= 0) {
02071                         (*clt.co) << "400 " PACKAGE " " VERSION ", service discontinued\r\n";
02072                         slog.p(Logger::Notice) << clt.client_logname << " discontinued due to Signal\n";
02073                         goto client_exit;
02074                 }
02075                 if (clt.ci->eof()) {
02076                         slog.p(Logger::Debug) << "NewsCache.cc input stream eof!\n";
02077                         break;
02078                 }
02079                 if (!clt.ci->good()) {
02080                         slog.p(Logger::Debug) << "NewsCache.cc input stream not good!\n";
02081                         break;
02082                 }
02083                 rp = req + strlen(req);
02084                 while (rp > req) {
02085                         rp--;
02086                         if (!isspace(*rp))
02087                                 break;
02088                         else
02089                                 *rp = '\0';
02090                 }
02091                 strcpy(oreq, req);
02092                 // FIXME: better solution?
02093                 if (strncasecmp(oreq, "authinfo", 8))
02094                         slog.p(Logger::Info) << clt.
02095                             client_logname << " " << oreq << "\n";
02096                 else
02097                         slog.p(Logger::Info) << clt.
02098                             client_logname << " authinfo\n";
02099 
02100                 // Split command into arguments
02101                 for (rp = req, argc = 0; *rp && argc < 256; rp++) {
02102                         if (isspace(*rp)) {
02103                                 *rp = '\0';
02104                         } else {
02105                                 if (rp == req || *(rp - 1) == '\0')
02106                                         argv[argc++] = rp;
02107                                 if (argc == 1)
02108                                         *rp = tolower(*rp);
02109                         }
02110                 }
02111                 if (!argc)
02112                         continue;
02113                 if (argc == 256) {
02114                         (*clt.co) << "500 Line too long\r\n";
02115                         continue;
02116                 }
02117                 // Call function for command
02118                 cmd = argv[0];
02119                 if (clt.auth_state == AUTH_REQUIRED &&
02120                     strcasecmp(cmd, "authinfo") != 0 &&
02121                     strcasecmp(cmd, "quit") != 0 &&
02122                     strcasecmp(cmd, "help") != 0) {
02123                         (*clt.
02124                          co) << "480 Authentication required (" << cmd <<
02125                        ")\r\n";
02126                         continue;
02127                 }
02128 
02129                 cmdp = clt.client_command_map.find(argv[0]);
02130                 if (cmdp == clt.client_command_map.end() || !cmdp->second->func) {
02131                         slog.p(Logger::Notice) << clt.client_logname
02132                             << " unrecognized " << oreq << "\n";
02133                         (*clt.co) << "500 What?\r\n";
02134                         continue;
02135                 }
02136 
02137                 errc = cmdp->second->func(&clt, argc, argv);
02138                 if (!(Cfg.LogStyle & Config::LogINN)) {
02139                         if (errc < 0) {
02140                                 if (strncasecmp(oreq, "authinfo", 8))
02141                                         slog.p(Logger::Notice) << clt.
02142                                                 client_logname << " failed " << oreq <<
02143                                                 "\n";
02144                                 else 
02145                                         slog.p(Logger::Notice) << clt.
02146                                                 client_logname << " failed authinfo for user  " <<
02147                                                 clt.auth_user << "\n";
02148                         }
02149                 if (clt.auth_failures >= clt.auth_max_failures) {
02150 
02151                         (*clt.  co) << "400 " PACKAGE " " VERSION
02152                        ", service discontinued (max passwords retries)\r\n";
02153                         goto client_exit;
02154                 }
02155                 }
02156         } while (errc == 0 || errc == -1);
02157 
02158       client_exit:
02159         if (clt.stat_artingrp) {
02160                 slog.p(Logger::Notice) << clt.client_logname
02161                     << " group " << clt.groupname
02162                     << " " << clt.stat_artingrp << "\n";
02163                 clt.stat_artingrp = 0;
02164         }
02165         slog.p(Logger::Notice) << clt.client_logname
02166             << " exit articles " << clt.stat_articles
02167             << " groups " << clt.stat_groups << "\n";
02168         clt.co->flush();
02169         delete clt.srvr;
02170 }

void nntpd  ) 
 

Definition at line 2172 of file NewsCache.cc.

References Config::CachePort, Cfg, cmnd, Logger::Error, fillHostStruct(), Config::Groupname, Config::ListenTo, Config::MaxConnections, Config::NiceServer, nnrpd(), nntp_connections, Logger::p(), Config::PidFile, Logger::print(), setugid(), slog, SOCKLEN_TYPE, Config::Username, and Xsignal.

Referenced by main().

02173 {
02174         int sock;
02175         struct sockaddr_in nproxy;
02176         struct servent *cport;
02177 
02178         struct sockaddr_in clt_sa;
02179         SOCKLEN_TYPE clt_salen;
02180 
02181         int clt_fd;
02182         int clt_pid = 0;
02183         int nice;
02184 
02185         slog.p(Logger::Notice) << "NewsCache Server Start\n";
02186 
02187         /* set nice value for master server */
02188 #ifdef HAVE_SETPRIORITY
02189         errno = 0;
02190         nice = Cfg.NiceServer;
02191         nice += getpriority(PRIO_PROCESS, 0);
02192         if (nice == -1 && errno != 0) {
02193                 slog.
02194                     p(Logger::
02195                       Error) << "getpriority failed: " << strerror(errno)
02196                     << "\n";
02197         } else {
02198                 if (setpriority(PRIO_PROCESS, 0, nice) == -1)
02199                         slog.
02200                             p(Logger::
02201                               Error) << "setpriority failed: " <<
02202                             strerror(errno) << "\n";
02203         }
02204 #endif
02205 
02206         /* nobody is connecting to NewsCache currently */
02207         nntp_connections = 0;
02208 
02209         {                       /* create socket and set some socket options */
02210                 int one = 1;
02211                 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
02212                         slog.
02213                             p(Logger::
02214                               Error) << "socket failed: " <<
02215                             strerror(errno) << "\n";
02216                         exit(1);
02217                 }
02218 
02219                 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
02220                                (char *) &one, sizeof(int)) < 0) {
02221                         slog.
02222                             p(Logger::
02223                               Error) << "setsockopt failed: " <<
02224                             strerror(errno) << "\n";
02225                 }
02226 
02227                 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
02228                                (char *) &one, sizeof(int)) < 0) {
02229                         slog.
02230                             p(Logger::
02231                               Error) << "setsockopt failed: " <<
02232                             strerror(errno) << "\n";
02233                 }
02234 
02235                 /* fill the sockaddr with the port we should listen too */
02236                 if (Cfg.CachePort[0] != '\0') {
02237                         // old variant
02238                         const char *cp = Cfg.CachePort;
02239                         nproxy.sin_family = AF_INET;
02240                         nproxy.sin_addr.s_addr = INADDR_ANY;
02241                         if (cp[0] != '#') {
02242                                 if ((cport =
02243                                      getservbyname(cp, "tcp")) == NULL) {
02244                                         slog.
02245                                             p(Logger::
02246                                               Error) << cmnd <<
02247                                             ": Can't resolve service " <<
02248                                             cp << "/tcp\n";
02249                                         exit(1);
02250                                 }
02251                                 nproxy.sin_port = cport->s_port;
02252                         } else {
02253                                 nproxy.sin_port = htons(atoi(cp + 1));
02254                         }
02255                 } else if (fillHostStruct(&nproxy, Cfg.ListenTo) == -1) {
02256                         slog.
02257                             p(Logger::
02258                               Error) << cmnd <<
02259                             ": Can't resolve parameter ListenTo: " << Cfg.
02260                             ListenTo << "\n";
02261                         exit(1);
02262                 }
02263         }                       /* end create socket and set some socket options */
02264 
02265         if (bind(sock, (struct sockaddr *) &nproxy, sizeof(nproxy)) < 0) {
02266                 slog.
02267                     p(Logger::
02268                       Error) << "can't bind socket: " << strerror(errno) <<
02269                     "\n";
02270                 exit(1);
02271         }
02272 
02273         {                       /* store pid in Cfg.PidFile */
02274                 ofstream pid(Cfg.PidFile);
02275                 pid << getpid() << endl;
02276                 if (!pid.good()) {
02277                         slog.
02278                             p(Logger::Warning) << "cannot open pid file\n";
02279                 }
02280         }
02281 
02282         setugid(Cfg.Username, Cfg.Groupname);
02283         listen(sock, 4);
02284         for (;;) {
02285                 /* Accept connection */
02286                 clt_salen = sizeof(clt_sa);
02287                 do {
02288                         errno = 0;
02289                         clt_fd =
02290                             accept(sock, (struct sockaddr *) &clt_sa,
02291                                    &clt_salen);
02292                         if (Xsignal >= 0) {
02293                                 close(sock);
02294                                 exit(0);
02295                         }
02296                 } while (errno == EINTR);
02297                 if (clt_fd < 0) {
02298                         slog.
02299                             p(Logger::
02300                               Warning) << "accept failed: " <<
02301                             strerror(errno) << "\n";
02302                         continue;
02303                 }
02304 #ifdef CONF_MultiClient
02305                 if (nntp_connections >= Cfg.MaxConnections
02306                     || (clt_pid = fork()) < 0) {
02307                         if (clt_pid < 0) {
02308                                 slog.
02309                                     p(Logger::
02310                                       Error) << "fork failed: " <<
02311                                     strerror(errno) << "\n";
02312                         }
02313                         write(clt_fd, "400 too many users\r\n", 21);
02314                         close(clt_fd);
02315                 } else {
02316                         // success
02317                         if (clt_pid == 0) {
02318                                 // child
02319                                 int one = 1;
02320                                 close(sock);
02321                                 if (setsockopt
02322                                     (clt_fd, SOL_SOCKET, SO_KEEPALIVE,
02323                                      (char *) &one, sizeof(int)) < 0) {
02324                                         slog.
02325                                             p(Logger::
02326                                               Error) <<
02327                                             "client setsockopt failed: " <<
02328                                             strerror(errno) << "\n";
02329                                 }
02330                                 try {
02331                                         nnrpd(clt_fd);
02332                                 } catch (sockerr e) {
02333                                         slog.p(Logger::Error) << "nnrpd caught "
02334                                                 << "sockbuf " << e.operation ()
02335                                                 << e.serrno ()
02336                                                 << " " << e.errstr () << "\n";
02337                                 } catch (UsageError e) {
02338                                         slog.p(Logger::Error) << "nnrpd caught "
02339                                                 << "UsageError ";
02340                                         e.print();
02341                                 } catch (NotAllowedError e) {
02342                                         slog.p(Logger::Error) << "nnrpd caught "
02343                                                 << "NotAllowdError ";
02344                                         e.print();
02345                                 } catch (NoSuchArticleError e) {
02346                                         slog.p(Logger::Error) << "nnrpd caught "
02347                                                 << "NoSuchArticleError ";
02348                                         e.print();
02349                                 } catch (DuplicateArticleError e) {
02350                                         slog.p(Logger::Error) << "nnrpd caught "
02351                                                 << "DuplicateArticleError ";
02352                                         e.print();
02353                                 } catch (NoSuchGroupError e) {
02354                                         slog.p(Logger::Error) << "nnrpd caught "
02355                                                 << "NoSuchGroupError ";
02356                                         e.print();
02357                                 } catch (NoNewsServerError e) {
02358                                         slog.p(Logger::Error) << "nnrpd caught "
02359                                                 << "NoNewsServerError ";
02360                                         e.print();
02361                                 } catch (NoSuchFieldError e) {
02362                                         slog.p(Logger::Error) << "nnrpd caught "
02363                                                 << "NoSuchFieldError ";
02364                                         e.print();
02365                                 } catch (NSError e) {
02366                                         slog.p(Logger::Error) << "nnrpd caught "
02367                                                 << "NSError ";
02368                                         e.print();
02369                                 } catch (AssertionError e) {
02370                                         slog.p(Logger::Error) << "nnrpd caught "
02371                                                 << "AssertionError ";
02372                                         e.print();
02373                                 } catch (IOError e) {
02374                                         slog.p(Logger::Error) << "nnrpd caught "
02375                                                 << "IOError ";
02376                                         e.print();
02377                                 } catch (SystemError e) {
02378                                         slog.p(Logger::Error) << "nnrpd caught "
02379                                                 << "SystemError ";
02380                                         e.print();
02381                                 } catch (Error e) {
02382                                         slog.p(Logger::Error) << "nnrpd caught "
02383                                                 << "Error ";
02384                                         e.print();
02385                                 } catch ( ... ) {
02386                                         slog.p(Logger::Error) << "nnrpd caught "
02387                                                 << "unknown!!"  << "\n";
02388                                 }
02389                                 close(clt_fd);
02390                                 exit(0);
02391                         }
02392                         //Parent
02393                         close(clt_fd);
02394                         nntp_connections++;
02395                 }
02396 #else
02397                 nnrpd(clt_fd);
02398                 close(clt_fd);
02399 #endif
02400         }
02401 
02402         close(sock);
02403 }

int ns_article ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 961 of file NewsCache.cc.

References CServer::article(), ASSERT2, ClientData::co, Newsgroup::freearticle(), Newsgroup::getarticle(), CServer::getgroup(), ClientData::groupname, ClientData::grp, ClientData::nbr, nsh_particle(), Logger::print(), slog, ClientData::srvr, ClientData::stat_articles, and ClientData::stat_artingrp.

00962 {
00963         if (argc > 2)
00964                 goto ns_article_error;
00965 
00966         // retrieve article|body|head by number?
00967         if (argc == 1 || isdigit(argv[1][0])) {
00968                 if (clt->groupname[0] == '\0') {
00969                         (*clt->
00970                          co) << "412 no newsgroup has been selected\r\n";
00971                         return -1;
00972                 }
00973                 try {
00974                         if (!clt->grp)
00975                                 clt->grp =
00976                                     clt->srvr->getgroup(clt->groupname);
00977                 }
00978                 catch(NoSuchGroupError & nsge) {
00979                         (*clt->co) << "411 no such newsgroup\r\n";
00980                         return -1;
00981                 }
00982                 catch(Error & e) {
00983                         (*clt->co) << "412 operation failed\r\n";
00984                         return -1;
00985                 }
00986 
00987                 if (argc == 1 && clt->nbr < 0) {
00988                         (*clt->
00989                          co) <<
00990                       "420 no current article has been selected\r\n";
00991                         return -1;
00992                 }
00993 
00994                 int nbr = (argc == 2) ? atoi(argv[1]) : clt->nbr;
00995 
00996                 ASSERT2(clt->grp->testdb());
00997                 Article *a;
00998                 
00999                 if ((a = clt->grp->getarticle(nbr)) == NULL) {
01000                         (*clt->
01001                          co) <<
01002                       "423 no such article number in this group\r\n";
01003                         return -1;
01004                 }
01005                 nsh_particle(clt, argv[0], nbr, a);
01006                 clt->grp->freearticle(a);
01007                 clt->nbr = nbr;
01008                 clt->stat_artingrp++;
01009                 clt->stat_articles++;
01010                 return 0;
01011         }
01012         // retrieve article|body|head by id?
01013         if (argv[1][0] == '<') {
01014                 try {
01015                         Article a;
01016                         clt->srvr->article(argv[1], &a);
01017                         nsh_particle(clt, argv[0], 0, &a);
01018                 }
01019                 catch(NoSuchArticleError nsae) {
01020                         (*clt->co) << "430 no such article id found\r\n";
01021                         return -1;
01022                 }
01023                 catch(ResponseError e) {
01024                         // error
01025                         (*clt->co) << e._got << "\r\n";
01026                         return -1;
01027                 }
01028                 catch(Error e) {
01029                         // error
01030                         (*clt->co) << "520 ???\r\n";
01031                         slog.
01032                             p(Logger::
01033                               Error) <<
01034                             "Internal Error? Please report to h.straub@aon.at\r\n";
01035                         e.print();
01036                         return -1;
01037                 }
01038                 clt->stat_artingrp++;
01039                 clt->stat_articles++;
01040                 return 0;
01041         }
01042         // error
01043       ns_article_error:
01044         switch (argv[0][0]) {
01045         case 'a':
01046                 (*clt->co) << "501 Syntax: article [nbr|<id>]\r\n";
01047                 return -1;
01048         case 'h':
01049                 (*clt->co) << "501 Syntax: head [nbr|<id>]\r\n";
01050                 return -1;
01051         case 'b':
01052                 (*clt->co) << "501 Syntax: body [nbr|<id>]\r\n";
01053                 return -1;
01054         }
01055         return -1;
01056 }

int ns_authinfo ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 903 of file NewsCache.cc.

References ClientData::auth_failure_sleep_time, ClientData::auth_failures, AUTH_OK, ClientData::auth_pass, ClientData::auth_state, ClientData::auth_user, check_authentication(), ClientData::co, INCORRECT_ORDER_SEQUENCE, OK_SEQUENCE, PASS_NEEDED_SEQUENCE, REJECT_SEQUENCE, and set_client_command_table().

00904 {
00905         // check arguments
00906         if (argc != 3)
00907                 goto ns_authinfo_error;
00908         if (strlen(argv[2]) > sizeof(clt->auth_user) - 1) {
00909                 (*clt->co) << REJECT_SEQUENCE " argument too long\r\n";
00910                 return -1;
00911         }
00912 
00913         if (!strcasecmp(argv[1], "user")) {
00914                 strcpy(clt->auth_user, argv[2]);
00915                 (*clt->co) << PASS_NEEDED_SEQUENCE " password please\r\n";
00916                 return 0;
00917         }
00918 
00919         if (!strcasecmp(argv[1], "pass")) {
00920                 if (clt->auth_user[0] == '\0') {
00921                         (*clt->
00922                          co) << INCORRECT_ORDER_SEQUENCE
00923                       " issue authinfo user first\r\n";
00924                         return -1;
00925                 }
00926                 strcpy(clt->auth_pass, argv[2]);
00927 
00928                 if (check_authentication(clt) < 0) {
00929                         sleep (clt->auth_failure_sleep_time*
00930                                         (++clt->auth_failures));
00931                         (*clt->
00932                          co) << REJECT_SEQUENCE << " Bad authinfo.\r\n";
00933                         return -1;
00934                 }
00935 
00936                 (*clt->co) << OK_SEQUENCE << " OK.\r\n";
00937                 clt->auth_state = AUTH_OK;
00938                 set_client_command_table(*clt);
00939 
00940                 return 0;
00941         }
00942         // error
00943       ns_authinfo_error:
00944         if (argc > 1) {
00945                 switch (tolower(argv[1][0])) {
00946                 case 'u':
00947                         (*clt->
00948                          co) << "501 Syntax: authinfo user username\r\n";
00949                         return -1;
00950                 case 'p':
00951                         (*clt->
00952                          co) << "501 Syntax: authinfo pass password\r\n";
00953                         return -1;
00954                 }
00955         }
00956         (*clt->
00957          co) << "501 Syntax: authinfo [user username|pass password]\r\n";
00958         return -1;
00959 }

int ns_date ClientData clt,
int  argc,
char *  argv[]
 

Author:
Thomas Gschwind Returns the gmtime. See RFC2980 DATE command.
Returns:
0 on success, -1 on error

Definition at line 1152 of file NewsCache.cc.

References ClientData::co, Logger::Error, Logger::p(), and slog.

01153 {
01154         struct tm *ltm;
01155         time_t conv;
01156         char buf[256];
01157 
01158         if (argc != 1) {
01159                 (*clt->co) << "501 Syntax: group Newsgroup\r\n";
01160                 return -1;
01161         }
01162         time(&conv);
01163         if ((ltm = gmtime(&conv)) == NULL) {
01164                 (*clt->co) << "500 gmtime failed\r\n";
01165                 slog.p(Logger::Error) << "ns_date() gmtime failed\n";
01166                 return -1;
01167         }
01168         sprintf(buf, "111 %04d%02d%02d%02d%02d%02d\r\n",
01169                 1900 + ltm->tm_year, ltm->tm_mon + 1, ltm->tm_mday,
01170                 ltm->tm_hour, ltm->tm_min, ltm->tm_sec);
01171         (*clt->co) << buf;
01172 
01173         return 0;
01174 }

int ns_group ClientData clt,
int  argc,
char *  argv[]
 

Author:
Thomas Gschwind Find the news server responsible for this newsgroup. Connect to it and select the newsgroup.

Definition at line 1181 of file NewsCache.cc.

References ClientData::access_entry, ClientData::co, GroupInfo::first(), GroupInfo::last(), NewsgroupFilter::matches(), GroupInfo::n(), GroupInfo::name(), Logger::p(), AccessEntry::read, selectgroup(), and slog.

01182 {
01183         if (argc != 2) {
01184                 (*clt->co) << "501 Syntax: group Newsgroup\r\n";
01185                 return -1;
01186         }
01187 
01188         if (clt->access_entry->read.matches(argv[1]) <= 0) {
01189                 (*clt->co) << "480 authentication required\r\n";
01190                 return 0;
01191         }
01192 
01193         GroupInfo *gi;
01194         if ((gi = selectgroup(clt, argv[1])) == NULL) {
01195                 (*clt->co) << "411 no such news group\r\n";
01196                 return -1;
01197         }
01198 
01199         (*clt->co) << "211 "
01200             << gi->n() << " "
01201             << gi->first() << " "
01202             << gi->last() << " " << gi->name() << " group selected\r\n";
01203 
01204         slog.p(Logger::Info) << "groupsize [" << gi->first() << ","
01205             << gi->last() << "]\n";
01206 
01207         return 0;
01208 }

int ns_help ClientData clt,
int  argc,
char *  argv[]
 

Author:
Thomas Gschwind Lists the available commands.

Definition at line 1214 of file NewsCache.cc.

References Config::Admin, Cfg, ClientData::client_command_map, ClientData::co, Logger::p(), slog, and VERB.

01215 {
01216         map < string, nnrp_command_t * >::iterator begin =
01217             clt->client_command_map.begin(), end = clt->client_command_map.end();
01218 
01219         VERB(slog.p(Logger::Debug) << "NewsCache::ns_help:\n");
01220         (*clt->co) << "100 Legal commands\r\n";
01221         while (begin != end) {
01222                 if (begin->second->func) {
01223                         (*clt->co) << "  " << begin->
01224                             first << " " << begin->second->desc << "\r\n";
01225                 }
01226                 ++begin;
01227         }
01228         (*clt->co) << "Report problems to " << Cfg.Admin << "\r\n.\r\n";
01229         return 0;
01230 }

int ns_lastnext ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1233 of file NewsCache.cc.

References ClientData::co, OverviewFmt::getfield(), CServer::getgroup(), Newsgroup::getover(), Newsgroup::getsize(), ClientData::groupname, ClientData::grp, ClientData::nbr, CServer::overviewfmt(), and ClientData::srvr.

01234 {
01235         if (argc != 1) {
01236                 switch (argv[0][0]) {
01237                 case 'l':
01238                         (*clt->co) << "501 Syntax: last\r\n";
01239                         return -1;
01240                 case 'n':
01241                         (*clt->co) << "501 Syntax: next\r\n";
01242                         return -1;
01243                 }
01244         }
01245         if (clt->groupname[0] == '\0') {
01246                 (*clt->co) << "412 No newsgroup currently selected\r\n";
01247                 return -1;
01248         }
01249         if (clt->nbr < 0) {
01250                 (*clt->
01251                  co) << "420 no current article has been selected\r\n";
01252                 return -1;
01253         }
01254         try {
01255                 if (!clt->grp)
01256                         clt->grp = clt->srvr->getgroup(clt->groupname);
01257         }
01258         catch(NoSuchGroupError & nsge) {
01259                 (*clt->co) << "411 no such news group\r\n";
01260                 return -1;
01261         }
01262         catch(Error & e) {
01263                 (*clt->co) << "412 operation failed\r\n";
01264                 return -1;
01265         }
01266 
01267         unsigned int f, i = clt->nbr, l;
01268         const char *o;
01269         string aid;
01270         OverviewFmt *ofmt = clt->srvr->overviewfmt();
01271         clt->grp->getsize(&f, &l);
01272         switch (argv[0][0]) {
01273         case 'l':
01274                 for (;;) {
01275                         i--;
01276                         if (i < f) {
01277                                 (*clt->
01278                                  co) << "422 No previous to retrieve\r\n";
01279                                 return -1;
01280                         }
01281                         o = clt->grp->getover(i);
01282                         if (o[0]) {
01283                                 aid = ofmt->getfield(o, "Message-ID:", 0);
01284                                 break;
01285                         }
01286                 }
01287                 break;
01288         case 'n':
01289                 for (;;) {
01290                         ++i;
01291                         if (i > l) {
01292                                 (*clt->
01293                                  co) << "421 No next to retrieve\r\n";
01294                                 return -1;
01295                         }
01296                         o = clt->grp->getover(i);
01297                         if (o[0]) {
01298                                 aid = ofmt->getfield(o, "Message-ID:", 0);
01299                                 break;
01300                         }
01301                 }
01302         }
01303         clt->nbr = i;
01304 
01305         (*clt->co) << "223 " << clt->nbr << " " << aid
01306             << " article retrieved - request text separately\r\n";
01307         return 0;
01308 }

int ns_list ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1379 of file NewsCache.cc.

References ClientData::access_entry, CServer::active(), ActiveDB::begin(), Cfg, ClientData::co, ActiveDB::end(), nlreadline(), CServer::overviewfmt(), NewsgroupFilter::setWildmat(), Config::SpoolDirectory, and ClientData::srvr.

01380 {
01381         if (argc <= 3) {
01382                 if (argc == 1 || strcasecmp(argv[1], "active") == 0) {
01383                         ActiveDB *active;
01384                         active = clt->srvr->active();
01385                         (*clt->
01386                          co) <<
01387                       "215 List of newsgroups (Group High Low Flags) follows\r\n";
01388                         try {
01389                                 NewsgroupFilter filter(clt->access_entry->
01390                                                        list);
01391                                 if (argc == 3)
01392                                         filter.setWildmat(argv[2]);
01393                                 for_each(active->begin(),
01394                                          active->end(),
01395                                          active_filter_group <
01396                                          print_list_active > (*clt->co,
01397                                                               filter));
01398                         }
01399                         catch(SystemError & se) {
01400                                 return -2;
01401                         }
01402                         (*clt->co) << ".\r\n";
01403                         return 0;
01404                 } else if (strcasecmp(argv[1], "active.times") == 0) {
01405                         ActiveDB *active;
01406                         active = clt->srvr->active();
01407                         (*clt->co) << "215 information follows\r\n";
01408                         try {
01409                                 NewsgroupFilter filter(clt->access_entry->
01410                                                        list);
01411                                 if (argc == 3)
01412                                         filter &= NewsgroupFilter(argv[2]);
01413 
01414                                 for_each(active->begin(),
01415                                          active->end(),
01416                                          active_filter_group <
01417                                          print_list_active_times >
01418                                          (*clt->co, filter));
01419                         }
01420                         catch(SystemError & se) {
01421                                 return -2;
01422                         }
01423                         (*clt->co) << ".\r\n";
01424                         return 0;
01425                 } else if (argc == 2) {
01426                         if (strcasecmp(argv[1], "extensions") == 0) {
01427                                 (*clt->
01428                                  co) << "202 extensions supported\r\n";
01429                                 (*clt->co) << " over\r\n";
01430                                 (*clt->co) << " authinfo user\r\n";
01431                                 (*clt->co) << ".\r\n";
01432                                 return 0;
01433                         } else if (strcasecmp(argv[1], "newsgroups") == 0) {
01434                                 char buf[MAXPATHLEN];
01435                                 string strg;
01436                                 sprintf(buf, "%s/.newsgroups",
01437                                         Cfg.SpoolDirectory);
01438                                 ifstream ifs(buf);
01439                                 (*clt->
01440                                  co) << "215 Description follows\r\n";
01441                                 for (;;) {
01442                                         nlreadline(ifs, strg);
01443                                         if (!ifs.good())
01444                                                 break;
01445                                         (*clt->co) << strg;
01446                                 }
01447                                 (*clt->co) << ".\r\n";
01448                                 return 0;
01449                         } else if (strcasecmp(argv[1], "overview.fmt") ==
01450                                    0) {
01451                                 (*clt->
01452                                  co) <<
01453                               "215 Order of fields in overview database\r\n"
01454                               << *(clt->srvr->overviewfmt()) << ".\r\n";
01455                                 return 0;
01456                         }
01457                 }
01458         }
01459 
01460         (*clt->
01461          co) <<
01462       "501 Syntax: list [active [wildmat]|active.times [time]|extensions|newsgroups|overview.fmt]\r\n";
01463         return -1;
01464 }

int ns_listgroup ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1470 of file NewsCache.cc.

References ClientData::access_entry, ClientData::co, CServer::getgroup(), ClientData::groupname, ClientData::grp, NewsgroupFilter::matches(), Newsgroup::printlistgroup(), AccessEntry::read, selectgroup(), and ClientData::srvr.

01471 {
01472         if (argc > 2) {
01473                 (*clt->co) << "501 Syntax: listgroup [Newsgroup]\r\n";
01474                 return -1;
01475         }
01476         if (argc == 1 && clt->groupname[0] == '\0') {
01477                 (*clt->co) << "412 Not currently in a newsgroup\r\n";
01478                 return -1;
01479         }
01480         if (argc == 2) {
01481                 if (selectgroup(clt, argv[1]) == NULL) {
01482                         (*clt->co) << "411 no such news group\r\n";
01483                         return -1;
01484                 }
01485                 if (clt->access_entry->read.matches(argv[1]) <= 0) {
01486                         (*clt->co) << "480 authentication required\r\n";
01487                         return 0;
01488                 }
01489         }
01490 
01491         try {
01492                 if (!clt->grp)
01493                         clt->grp = clt->srvr->getgroup(clt->groupname);
01494         }
01495         catch(NoSuchGroupError & nsge) {
01496                 (*clt->co) << "411 no such news group\r\n";
01497                 return -1;
01498         }
01499         catch(Error & e) {
01500                 (*clt->co) << "412 operation failed\r\n";
01501                 e.print();
01502                 return -1;
01503         }
01504 
01505         (*clt->co) << "211 list of article numbers follow\r\n";
01506         clt->grp->printlistgroup(*clt->co);
01507         (*clt->co) << ".\r\n";
01508         return 0;
01509 }

int ns_mode ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1511 of file NewsCache.cc.

References ClientData::co, and PACKAGE.

01512 {
01513         if (argc != 2 ||
01514             (strcasecmp(argv[1], "reader") != 0 &&
01515              strcasecmp(argv[1], "query") != 0)) {
01516                 (*clt->co) << "501 Syntax: mode (reader|query)\r\n";
01517                 return -1;
01518         }
01519         (*clt->
01520          co) << "200 " PACKAGE " " VERSION ", accepting NNRP commands\r\n";
01521         return 0;
01522 }

int ns_newgroups ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1528 of file NewsCache.cc.

References ClientData::access_entry, CServer::active(), ActiveDB::begin(), ClientData::co, DD2INT, ActiveDB::end(), and ClientData::srvr.

01529 {
01530         if (argc < 3 || argc > 5) {
01531               ns_newgroups_error:
01532                 (*clt->
01533                  co) <<
01534               "501 Syntax:  NEWGROUPS date time [GMT] [<wildmat>]\r\n";
01535                 return -1;
01536         }
01537 
01538         int i, y4, is_gmt = 0;
01539         struct tm ltm;
01540         time_t lt;
01541         char *p;
01542 
01543         // check first two arguments, y4 indicates whether year has 4 digits
01544         for (i = 0; isdigit(argv[2][i]); i++);
01545         if (i != 6 || argv[2][i])
01546                 goto ns_newgroups_error;
01547         for (y4 = 0; isdigit(argv[1][y4]); y4++);
01548         if ((y4 != 8 && y4 != 6) || argv[1][y4])
01549                 goto ns_newgroups_error;
01550         y4 -= 4;
01551 
01552         // check whether time/date is specified in GMT
01553         if (argc >= 4) {
01554                 if (strcasecmp(argv[3], "gmt") != 0 &&
01555                     strcasecmp(argv[3], "utc") != 0) {
01556                         goto ns_newgroups_error;
01557                 }
01558                 is_gmt = 1;
01559         }
01560         // fill in ltm with supplied values
01561         p = argv[1];
01562         if (y4 > 2) {
01563                 i = DD2INT(p);
01564                 p += 2;
01565                 ltm.tm_year = i * 100 + DD2INT(p) - 1900;
01566                 p += 2;
01567         } else {
01568                 struct tm *now;
01569                 int yr;
01570 
01571                 // draft-ietf-nntpext-base-04.txt:
01572                 // If the first two digits of the year are not specified,
01573                 // the year is to be taken from the current century if YY
01574                 // is smaller than or equal to the current year,
01575                 // otherwise the year is from the previous century.
01576                 time(&lt);
01577                 now = is_gmt ? gmtime(&lt) : localtime(&lt);
01578                 yr = now->tm_year % 100;
01579 
01580                 ltm.tm_year = DD2INT(p);
01581                 p += 2;
01582                 if (ltm.tm_year > yr)
01583                         ltm.tm_year += now->tm_year - yr - 100;
01584                 else
01585                         ltm.tm_year += now->tm_year - yr;
01586         }
01587         ltm.tm_mon = DD2INT(p) - 1;
01588         p += 2;                 // tm_mon has a range of 0(Jan)--11(Dec)!!!
01589         ltm.tm_mday = DD2INT(p);
01590 
01591         p = argv[2];
01592         ltm.tm_hour = DD2INT(p);
01593         p += 2;
01594         ltm.tm_min = DD2INT(p);
01595         p += 2;
01596         ltm.tm_sec = DD2INT(p);
01597 
01598 #ifdef HAVE_TZNAME
01599         ltm.tm_isdst = daylight;
01600 
01601         lt = mktime(&ltm);
01602         if (lt == -1)
01603                 goto ns_newgroups_error;
01604 
01605         // correct timezone if time/date is given in GMT
01606         if (is_gmt) {
01607                 lt -= timezone;
01608         }
01609 #else
01610         struct tm *plt;
01611 
01612         time(&lt);
01613         plt = localtime(&lt);
01614 
01615         ltm.tm_isdst = plt->tm_isdst;
01616         ltm.tm_gmtoff = plt->tm_gmtoff;
01617 
01618         lt = mktime(&ltm);
01619         if (lt == -1)
01620                 goto ns_newgroups_error;
01621 #endif
01622 
01623         ActiveDB *active;
01624         try {
01625                 active = clt->srvr->active();
01626         }
01627         catch(Error & e) {
01628                 (*clt->co) << "410 operation failed\r\n";
01629                 return -1;
01630         }
01631         (*clt->co) << "231 list of new groups follows " << lt << "\r\n";
01632         try {
01633                 NewsgroupFilter filter();
01634 
01635                 for_each(active->begin(),
01636                          active->end(),
01637                          active_filter_group_time <
01638                          print_list_active_times > (*clt->co,
01639                                                     clt->access_entry->
01640                                                     list, lt));
01641         }
01642         catch(SystemError & se) {
01643                 return -2;
01644         }
01645         (*clt->co) << ".\r\n";
01646         return 0;
01647 }

int ns_post ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1651 of file NewsCache.cc.

References ClientData::access_entry, ClientData::ci, ClientData::co, Article::getfield(), newsgroups, Logger::p(), CServer::post(), AccessEntry::postTo, Article::read(), slog, ClientData::srvr, and VERB.

01652 {
01653         VERB(slog.p(Logger::Debug) << "NewsCache::ns_post\n");
01654         if (argc != 1) {
01655                 (*clt->co) << "501 Syntax: post\r\n";
01656                 return -1;
01657         }
01658 
01659         Article art;
01660 
01661         try {
01662                 // request article to be posted
01663                 (*clt->co) << "340 send article to be posted.\r\n";
01664                 clt->co->flush();
01665                 art.read(*clt->ci);
01666 
01667                 // check whether client is authorized to post this article.
01668                 string newsgroups = art.getfield("newsgroups:");
01669                 unsigned int i1 = 0, i2 = newsgroups.find(",");
01670                 for (;;) {
01671                         string group = newsgroups.substr(i1, i2);
01672                         if (clt->access_entry->postTo.
01673                             matches(group.c_str()) <= 0) {
01674                                 (*clt->
01675                                  co) << "480 authentication required\r\n";
01676                                 return 0;
01677                         }
01678                         if (i2 == string::npos)
01679                                 break;
01680                         i1 = i2 + 1;
01681                         i2 = newsgroups.find(",", i1);
01682                 }
01683         }
01684         catch(InvalidArticleError & iae) {
01685                 (*clt->co) << "441 invalid article\r\n";
01686                 return -1;
01687         }
01688         catch(NoSuchFieldError & nsfe) {
01689                 (*clt->co) << "441 invalid article\r\n";
01690                 return -1;
01691         }
01692 
01693         try {
01694                 // client is authorized to post the article
01695                 clt->srvr->post(&art);
01696                 (*clt->co) << "240 Article posted\r\n";
01697                 return 0;
01698         }
01699         catch(InvalidArticleError & iae) {
01700                 (*clt->co) << "441 invalid article\r\n";
01701                 return -1;
01702         }
01703         catch(NotAllowedError & nae) {
01704                 (*clt->co) << "440 posting not allowed\r\n";
01705                 return -1;
01706         }
01707         catch(Error & e) {
01708                 (*clt->co) << "449 operation failed\r\n";
01709                 return -1;
01710         }
01711 }

int ns_quit ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1713 of file NewsCache.cc.

References ClientData::co.

01714 {
01715         (*clt->co) << "205 Good bye\r\n";
01716         return 1;
01717 }

int ns_stat ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1058 of file NewsCache.cc.

References CServer::article(), ASSERT2, ClientData::co, Article::getfield(), OverviewFmt::getfield(), CServer::getgroup(), Newsgroup::getover(), ClientData::groupname, ClientData::grp, ClientData::nbr, CServer::overviewfmt(), Logger::print(), slog, and ClientData::srvr.

01059 {
01060         /* Offene Punkte:
01061            ** stat auf nummer die nicht vorhanden ist, ergibt:
01062            ** 223 351  status
01063            ** das ist falsch, sollte sein:
01064            ** 423 No Such Article In Group
01065            **
01066          */
01067         if (argc > 2)
01068                 goto ns_stat_error;
01069 
01070         // stat by number?
01071         if (argc == 1 || isdigit(argv[1][0])) {
01072                 // fetch article by number
01073                 if (clt->groupname[0] == '\0') {
01074                         (*clt->
01075                          co) << "412 no newsgroup has been selected\r\n";
01076                         return -1;
01077                 }
01078                 try {
01079                         if (!clt->grp)
01080                                 clt->grp =
01081                                     clt->srvr->getgroup(clt->groupname);
01082                 }
01083                 catch(NoSuchGroupError & nsge) {
01084                         (*clt->co) << "411 no such newsgroup\r\n";
01085                         return -1;
01086                 }
01087                 catch(Error & e) {
01088                         (*clt->co) << "412 operation failed\r\n";
01089                         return -1;
01090                 }
01091 
01092                 if (argc == 1 && clt->nbr < 0) {
01093                         (*clt->
01094                          co) <<
01095                       "420 no current article has been selected\r\n";
01096                         return -1;
01097                 }
01098 
01099                 int nbr = (argc == 2) ? atoi(argv[1]) : clt->nbr;
01100 
01101                 ASSERT2(clt->grp->testdb());
01102                 OverviewFmt *of = clt->srvr->overviewfmt();
01103                 const char *o = clt->grp->getover(nbr);
01104                 (*clt->co) << "223 " << nbr << " " << of->getfield(o,
01105                                                                    "Message-ID:",
01106                                                                    0)
01107                     << " status \r\n";
01108                 return 0;
01109         }
01110         // stat by id?
01111         if (argv[1][0] == '<') {
01112                 //(*clt->co) << "223 0 " << argv[1] << " status\r\n";
01113                 Article a;
01114                 try {
01115                         clt->srvr->article(argv[1], &a);
01116                         //nsh_particle(clt, argv[0], 0, &a);
01117                 }
01118                 catch(NoSuchArticleError nsae) {
01119                         (*clt->co) << "430 no such article id found\r\n";
01120                         return -1;
01121                 }
01122                 catch(ResponseError e) {
01123                         // error
01124                         (*clt->co) << e._got << "\r\n";
01125                         return -1;
01126                 }
01127                 catch(Error e) {
01128                         // error
01129                         (*clt->co) << "520 ???\r\n";
01130                         slog.
01131                             p(Logger::
01132                               Error) <<
01133                             "Internal Error? Please report to h.straub@aon.at\r\n";
01134                         e.print();
01135                         return -1;
01136                 }
01137                 string mid = a.getfield("Message-ID:");
01138                 (*clt->co) << "223 0 " << mid << " status\r\n";
01139                 return 0;
01140         }
01141         // error
01142       ns_stat_error:
01143         (*clt->co) << "501 Syntax: stat [nbr|<id>]\r\n";
01144         return -1;
01145 }

int ns_xdebug ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1797 of file NewsCache.cc.

References ClientData::access_entry, Cfg, ClientData::co, and Config::printParameters().

01798 {
01799         if (argc == 3) {
01800                 if (strcmp(argv[1], "dump") == 0) {
01801                         if (strcmp(argv[2], "authorization") == 0) {
01802                                 (*clt->
01803                                  co) <<
01804                               "xxx authorization data follows\r\n";
01805                                 (*clt->co) << *clt->access_entry << "\r\n";
01806                                 (*clt->co) << ".\r\n";
01807                         }
01808                         if (strcmp(argv[2], "configuration") == 0) {
01809                                 (*clt->
01810                                  co) <<
01811                               "xxx configuration data follows\r\n";
01812                                 Cfg.printParameters (clt->co);
01813                                 (*clt->co) << ".\r\n";
01814                         }
01815                 }
01816                 return 0;
01817         }
01818 
01819         if (argc == 2) {
01820                 if (strcmp(argv[1], "help") == 0) {
01821                         (*clt->co) << "Valid commands:\r\n";
01822                         (*clt->co) << "xdebug dump authorization:\r\n";
01823                         (*clt->co) << "xdebug dump configuration:\r\n";
01824                         (*clt->co) << ".\r\n";
01825                         return 0;
01826                 }
01827         }
01828 
01829         (*clt->co) << "501 Syntax: xdebug help\r\n";
01830         return -1;
01831 }

int ns_xmotd ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1719 of file NewsCache.cc.

References ClientData::co.

01720 {
01721         (*clt->co) << "500 not yet supported\r\n";
01722         return -1;
01723 }

int ns_xover ClientData clt,
int  argc,
char *  argv[]
 

Definition at line 1733 of file NewsCache.cc.

References ASSERT2, ClientData::co, CServer::getgroup(), ClientData::groupname, ClientData::grp, ClientData::nbr, Newsgroup::printheaderdb(), Newsgroup::printoverdb(), and ClientData::srvr.

01734 {
01735         int i = 1, fst, lst;
01736         char *p;
01737 
01738         if (clt->groupname[0] == '\0') {
01739                 (*clt->co) << "412 No newsgroup currently selected\r\n";
01740                 return -1;
01741         }
01742         if (strcmp(argv[0], "xhdr") == 0) {
01743                 i = 2;
01744         }
01745         switch (argc - i) {
01746         case 0:
01747                 fst = lst = clt->nbr;
01748                 break;
01749         case 1:
01750                 p = argv[i];
01751                 if (isdigit(*p))
01752                         fst = lst = strtol(argv[i], &p, 10);
01753                 if ((*p) == '\0')
01754                         break;
01755                 if ((*p) == '-') {
01756                         lst = UINT_MAX;
01757                         p++;
01758                         if (isdigit(*p))
01759                                 lst = strtol(p, &p, 10);
01760                         if ((*p) == '\0')
01761                                 break;
01762                 }
01763         default:
01764                 (*clt->co) << "501 Syntax: xover [range]\r\n";
01765                 return -1;
01766         }
01767         try {
01768                 if (!clt->grp)
01769                         clt->grp = clt->srvr->getgroup(clt->groupname);
01770         }
01771         catch(NoSuchGroupError & nsge) {
01772                 (*clt->co) << "411 no such news group\r\n";
01773                 return -1;
01774         }
01775         catch(Error & e) {
01776                 e.print();
01777                 (*clt->co) << "412 operation failed\r\n";
01778                 return -1;
01779         }
01780 
01781         ASSERT2(clt->grp->testdb());
01782         switch (i) {
01783         case 1:
01784                 (*clt->co) << "224 Overview information follows\r\n";
01785                 clt->grp->printoverdb(*clt->co, fst, lst);
01786                 break;
01787         case 2:
01788                 (*clt->
01789                  co) << "221 " << p << "[" << fst << "-" << lst << "]\r\n";
01790                 clt->grp->printheaderdb(*clt->co, argv[1], fst, lst);
01791                 break;
01792         }
01793         (*clt->co) << ".\r\n";
01794         return 0;
01795 }

void nsh_particle ClientData clt,
char *  cmnd,
int  nbr,
Article a
 

Definition at line 867 of file NewsCache.cc.

References cmnd, ClientData::co, Article::getfield(), Article::length(), Logger::p(), slog, and Article::write().

Referenced by ns_article().

00868 {
00869         string aid = a->getfield("Message-ID:");
00870 
00871         switch (cmnd[0]) {
00872         case 'a':
00873                 (*clt->co) << "220 " << nbr << " " << aid
00874                     << " article retrieved - head and body follow\r\n";
00875                 (*clt->co) << *a << ".\r\n";
00876                 slog.p(Logger::Info) << "articlesize " << clt->
00877                     groupname << ":" << nbr << " " << a->length() << "\n";
00878                 break;
00879         case 'h':
00880                 (*clt->co) << "221 " << nbr << " " << aid
00881                     << " article retrieved - head follows\r\n";
00882                 a->write(*clt->co, Article::Head);
00883                 (*clt->co) << ".\r\n";
00884                 break;
00885         case 'b':
00886                 (*clt->co) << "222 " << nbr << " " << aid
00887                     << " article retrieved - body follows\r\n";
00888                 a->write(*clt->co, Article::Body);
00889                 (*clt->co) << ".\r\n";
00890                 slog.p(Logger::Info) << "articlesize " << clt->
00891                     groupname << ":" << nbr << " " << a->length() << "\n";
00892                 break;
00893         }
00894 }

char** seekfile const char *  filename,
const char *  username
 

Definition at line 398 of file NewsCache.cc.

References slog.

Referenced by check_auth_file().

00399 {
00400         FILE *F;
00401         static char buf[1024];
00402         char *p;
00403         int i;
00404 
00405         static char *fields[8];
00406         int fields_n = sizeof(fields) / sizeof(fields[0]);
00407 
00408         if ((F = fopen(filename, "r")) == NULL) {
00409                 slog.
00410                     p(Logger::
00411                       Error) << "cannot fopen " << filename << "\n";
00412                 return NULL;
00413         }
00414 
00415         while (fgets(buf, sizeof(buf), F) != NULL) {
00416                 p = buf + strlen(buf) - 1;
00417                 while (p > buf && isspace(*p))
00418                         *p-- = '\0';
00419                 p = buf;
00420                 while (isspace(*p))
00421                         p++;
00422                 if (*p == '#' || *p == '\0')
00423                         continue;
00424 
00425                 fields[0] = p;
00426                 for (i = 1; *p && i < fields_n - 1; p++) {
00427                         if (*p == ':') {
00428                                 *p = '\0';
00429                                 fields[i++] = p + 1;
00430                         }
00431                 }
00432                 fields[i] = NULL;
00433 
00434                 if (strcmp(username, fields[0]) == 0) {
00435                         (void) fclose(F);
00436                         return fields;
00437                 }
00438         }
00439         (void) fclose(F);
00440         return NULL;
00441 }

GroupInfo* selectgroup ClientData clt,
const char *  group
 

Definition at line 826 of file NewsCache.cc.

References GroupInfo::first(), NServer::freegroup(), CServer::groupinfo(), ClientData::groupname, ClientData::grp, GroupInfo::last(), ClientData::nbr, Logger::p(), Newsgroup::setsize(), slog, ClientData::srvr, ClientData::stat_artingrp, ClientData::stat_groups, and VERB.

Referenced by ns_group(), and ns_listgroup().

00827 {
00828         GroupInfo *gi;
00829         VERB(slog.
00830              p(Logger::
00831                Debug) << "NewsCache selectgroup (" << group << ")\n");
00832 
00833         try {
00834                 gi = clt->srvr->groupinfo(group);
00835         } catch(NSError & nse) {
00836                 return NULL;
00837         }
00838         catch(...) {
00839                 return NULL;
00840         }
00841         // Reset Article Pointer
00842         if (gi->first() <= gi->last())
00843                 clt->nbr = gi->first();
00844         else
00845                 clt->nbr = -1;
00846         if (strcmp(clt->groupname, group) != 0) {
00847                 if (clt->grp)
00848                         clt->srvr->freegroup(clt->grp);
00849                 clt->grp = NULL;
00850                 clt->stat_groups++;
00851                 if (clt->stat_artingrp) {
00852                         slog.p(Logger::Notice) << clt->
00853                             client_logname << " group " << clt->
00854                             groupname << " " << clt->stat_artingrp << "\n";
00855                         clt->stat_artingrp = 0;
00856                 }
00857                 strcpy(clt->groupname, group);
00858         } else {
00859                 //FIXME! NServer has to maintain a list of all the allocated
00860                 //FIXME! newsgroups and should call this function itself!!!
00861                 if (clt->grp)
00862                         clt->grp->setsize(gi->first(), gi->last());
00863         }
00864         return gi;
00865 }

void set_client_command_table ClientData clt  ) 
 

Definition at line 1851 of file NewsCache.cc.

References ClientData::access_entry, AccessEntry::access_flags, ClientData::client_command_map, NNRPCommandMap::disableDebug(), NNRPCommandMap::disablePost(), NNRPCommandMap::disableRead(), and NNRPCommandMap::enableAll().

Referenced by nnrpd(), and ns_authinfo().

01852 {
01853         clt.client_command_map.enableAll();
01854         if (!(clt.access_entry->access_flags & AccessEntry::af_read)) {
01855                 clt.client_command_map.disableRead();
01856         }
01857 
01858         if (!(clt.access_entry->access_flags & AccessEntry::af_post)) {
01859                 clt.client_command_map.disablePost ();
01860         }
01861 
01862         if (!(clt.access_entry->access_flags & AccessEntry::af_debug)) {
01863                 clt.client_command_map.disableDebug ();
01864         }
01865 }

void sigchld int  num  ) 
 

Definition at line 2405 of file NewsCache.cc.

References nntp_connections, Logger::p(), sigchld(), and slog.

Referenced by main(), and sigchld().

02406 {
02407         int pid;
02408         int st;
02409 
02410         slog.p(Logger::Debug) << "receiving signal SIGCHLD: " << num << "\n";
02411         /* Reinstall the signal handler */
02412 #ifdef HAVE_SIGACTION
02413         struct sigaction action;
02414         action.sa_handler = sigchld;
02415         sigemptyset(&action.sa_mask);
02416         action.sa_flags = 0;
02417         sigaction(num, &action, NULL);
02418 #else
02419         signal(num, sigchld);
02420 #endif
02421 
02422         while ((pid = waitpid(0, &st, WNOHANG)) > 0) {
02423                 if (WIFEXITED(st) || WIFSIGNALED(st)) {
02424                         // child terminated
02425                         nntp_connections--;
02426                         if (st) {
02427                                 if (WIFEXITED(st)) {
02428                                         slog.
02429                                             p(Logger::
02430                                               Error) << pid << " returned "
02431                                             << WEXITSTATUS(st) << "\n";
02432                                 } else if (WIFSIGNALED(st)) {
02433                                         slog.
02434                                             p(Logger::
02435                                               Error) << pid <<
02436                                             " caught signal " <<
02437                                             WTERMSIG(st) << "\n";
02438                                 }
02439                         }
02440                 }
02441         }
02442 }


Variable Documentation

Config Cfg
 

Definition at line 299 of file NewsCache.cc.

Referenced by catchsighup(), clean(), main(), nnrpd(), nntpd(), ns_help(), ns_list(), ns_xdebug(), readgroups(), and update().

int clientTimeoutReached = 0
 

Definition at line 141 of file NewsCache.cc.

Referenced by catchsigalarm(), and nnrpd().

const char* cmnd
 

Definition at line 143 of file NewsCache.cc.

Referenced by main(), nntpd(), nsh_particle(), and nvflock().

char config_file[MAXPATHLEN]
 

Definition at line 298 of file NewsCache.cc.

Referenced by catchsighup(), and main().

char* ConfigurationOptions[]
 

Definition at line 52 of file NewsCache.cc.

Referenced by main().

int nntp_connections
 

Definition at line 302 of file NewsCache.cc.

Referenced by nntpd(), and sigchld().

Logger slog
 

Definition at line 142 of file NewsCache.cc.

int Xsignal
 

Definition at line 301 of file NewsCache.cc.

Referenced by catchsignal(), main(), nnrpd(), nntpd(), readgroups(), and update().


Generated on Fri Aug 20 10:58:09 2004 for NewsCache by doxygen 1.3.6-20040222