chiark / gitweb /
fix warnings
[nntp-merge-chiark.git] / nnrpwrap.c
1 /**/
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <errno.h>
8 #include <unistd.h>
9 #include <sys/socket.h>
10 #include <sys/time.h>
11 #include <arpa/inet.h>
12 #include <netinet/in.h>
13
14 #include "md5.h"
15
16 #define MAX_SECRET 64
17 #define NNRPDREAL "/usr/sbin/nnrpd.real"
18
19 static void chopspaces(char *buf) {
20   int n;
21   n= strlen(buf);
22   while (n > 0 && isspace(buf[n-1])) n--;
23   buf[n]= 0;
24 }
25
26 int main(int argc, char **argv) {
27   char *p, *q, **argvs;
28   unsigned char message[16+MAX_SECRET], expect[16];
29   char responsebuf[300];
30   char sesamebuf[MAX_SECRET*2+100];
31   struct sockaddr_in peername;
32   int c, n, l;
33   socklen_t namesize;
34   struct MD5Context md5ctx;
35   FILE *file;
36   unsigned long ul;
37   unsigned short us;
38   struct timeval timevab;
39
40   argvs= argv;
41   while ((p= *++argvs)) {
42     if (*p++ != '-') break;
43     c= *p++;
44     if (!c) break;
45     do {
46       if (c == 'r') {
47         if (*++argvs) {
48           printf("400 %s\r\n",*argvs); exit(1);
49         }
50         --argvs;
51         break;
52       } else if (c == 's' || c == 'S') {
53         if (!*++argvs) --argvs;
54         break;
55       }
56       c= *p++;
57     } while (c);
58   }
59
60   if (gettimeofday(&timevab,(void*)0)) {
61     printf("400 what year is it: %s\r\n",strerror(errno));
62     exit(1);
63   }
64   memcpy(message,&timevab.tv_sec,4);
65   ul= timevab.tv_usec; memcpy(message+4,&ul,4);
66   namesize= sizeof(peername);
67   if (getsockname(fileno(stdin),(struct sockaddr*)&peername,&namesize) &&
68       namesize == sizeof(peername) &&
69       peername.sin_family == AF_INET) {
70     memcpy(message+8,&peername.sin_addr,4);
71     memcpy(message+12,&peername.sin_port,2);
72   } else {
73     memset(message+8,'x',6);
74   }
75   us= getpid(); memcpy(message+14,&us,2);
76
77   printf("480 ");
78   for (n=0; n<16; n++) {
79     printf("%s%02x", n?":":"", message[n]);
80   }
81   printf("  halt !  who goes there ?\r\n");
82   if (fflush(stdout) || ferror(stdout)) { perror("stdout challenge"); exit(1); }
83   if (!fgets(responsebuf,sizeof(responsebuf),stdin)) {
84     if (ferror(stdin)) perror("stdin response");
85     else fprintf(stderr,"stdin response EOF\n");
86     exit(1);
87   }
88   chopspaces(responsebuf);
89   p= strchr(responsebuf,' ');
90   if (p) *p++= 0;
91   if (!strcasecmp(responsebuf,"QUIT")) {
92     printf("205 please remember your papers next time.\r\n");
93     exit(0);
94   }
95   if (strcasecmp(responsebuf,"PASS")) {
96     printf("500 guards !  guards !\r\n"
97            "400 this client was just leaving.\r\n");
98     exit(1);
99   }
100   if (!p) {
101     printf("501 fail.\r\n"
102            "400 we don't want failures here.\r\n");
103     exit(1);
104   }
105   file= fopen("/etc/news/sesame","r");
106   if (!file) {
107     printf("400 suddenly i can't see anything: %s\r\n",strerror(errno));
108     exit(1);
109   }
110   do {
111     if (!fgets(sesamebuf,sizeof(sesamebuf),file)) {
112       if (ferror(file)) {
113         printf("400 i'm not sure about that: %s\r\n",strerror(errno));
114       } else {
115         printf("400 happiness is mandatory.\r\n");
116       }
117       exit(1);
118     }
119     chopspaces(sesamebuf);
120   } while (!*sesamebuf || *sesamebuf == '#' || !(q= strchr(sesamebuf,' ')));
121   *q++= 0;
122   l= strlen(q);
123   if (l>MAX_SECRET) { printf("400 i feel all bloated.\r\n"); exit(1); }
124   memcpy(message+16,q,l);
125
126   MD5Init(&md5ctx);
127   MD5Update(&md5ctx,message,16+l);
128   MD5Final(expect,&md5ctx);
129
130   for (n=0; n<16; n++) sprintf(sesamebuf+n*3,"%02x:",expect[n]);
131   sesamebuf[47]= 0;
132   if (!strcasecmp(p,sesamebuf)) {
133     execvp(NNRPDREAL,argv);
134     printf("400 o master, i have failed you: %s\r\n",strerror(errno));
135     exit(1);
136   }
137   printf("502 impostor !\r\n"
138          "400 do not darken my door again.\r\n");
139   exit(1);
140 }