5958a3607e6dfab20a076748e3a9288065f322e3
[citadel.git] / citadel / modules / nntp / serv_nntp.c
1 /*
2  * NNTP server module FIXME THIS IS NOT FINISHED
3  *
4  * Copyright (c) 2014 by the citadel.org team
5  *
6  * This program is open source software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 3.
8  *  
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include "sysdep.h"
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <stdio.h>
19 #include <termios.h>
20 #include <fcntl.h>
21 #include <signal.h>
22 #include <pwd.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <syslog.h>
26
27 #if TIME_WITH_SYS_TIME
28 # include <sys/time.h>
29 # include <time.h>
30 #else
31 # if HAVE_SYS_TIME_H
32 #  include <sys/time.h>
33 # else
34 #  include <time.h>
35 # endif
36 #endif
37
38 #include <sys/wait.h>
39 #include <ctype.h>
40 #include <string.h>
41 #include <limits.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <libcitadel.h>
46 #include "citadel.h"
47 #include "server.h"
48 #include "citserver.h"
49 #include "support.h"
50 #include "config.h"
51 #include "control.h"
52 #include "user_ops.h"
53 #include "room_ops.h"
54 #include "database.h"
55 #include "msgbase.h"
56 #include "internet_addressing.h"
57 #include "genstamp.h"
58 #include "domain.h"
59 #include "clientsocket.h"
60 #include "locate_host.h"
61 #include "citadel_dirs.h"
62 #include "ctdl_module.h"
63
64 /*
65  * Here's where our NNTP session begins its happy day.
66  */
67 void nntp_greeting(void)
68 {
69         strcpy(CC->cs_clientname, "NNTP session");
70         CC->cs_flags |= CS_STEALTH;
71
72         /* CC->session_specific_data = malloc(sizeof(citnntp));
73         memset(NNTP, 0, sizeof(citnntp));
74         */
75
76         if (CC->nologin==1) {
77                 cprintf("451 Too many connections are already open; please try again later.\r\n");
78                 CC->kill_me = KILLME_MAX_SESSIONS_EXCEEDED;
79                 return;
80         }
81
82         /* Note: the FQDN *must* appear as the first thing after the 220 code.
83          * Some clients (including citmail.c) depend on it being there.
84          */
85         cprintf("200 %s NNTP Citadel server is not finished yet\r\n", config.c_fqdn);
86 }
87
88
89 /*
90  * NNTPS is just like NNTP, except it goes crypto right away.
91  */
92 void nntps_greeting(void) {
93         CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
94 #ifdef HAVE_OPENSSL
95         if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;          /* kill session if no crypto */
96 #endif
97         nntp_greeting();
98 }
99
100
101
102 /*
103  * implements the STARTTLS command
104  */
105 void nntp_starttls(void)
106 {
107         char ok_response[SIZ];
108         char nosup_response[SIZ];
109         char error_response[SIZ];
110
111         sprintf(ok_response, "382 Begin TLS negotiation now\r\n");
112         sprintf(nosup_response, "502 Can not initiate TLS negotiation\r\n");
113         sprintf(error_response, "580 Internal error\r\n");
114         CtdlModuleStartCryptoMsgs(ok_response, nosup_response, error_response);
115 }
116
117
118 void nntp_noop(void)
119 {
120         cprintf("250 NOOP\r\n");
121 }
122
123
124 void nntp_capabilities(void)
125 {
126         cprintf("101 Capability list:\r\n");
127 #ifdef HAVE_OPENSSL
128         cprintf("STARTTLS\r\n");
129 #endif
130         if (!CC->logged_in) {
131                 cprintf("AUTHINFO USER\r\n");
132         }
133         cprintf(".\r\n");
134 }
135
136
137 void nntp_quit(void)
138 {
139         cprintf("221 Goodbye...\r\n");
140         CC->kill_me = KILLME_CLIENT_LOGGED_OUT;
141 }
142
143
144 void nntp_cleanup(void)
145 {
146         /* nothing here yet */
147 }
148
149
150
151 /*
152  * Implements the AUTHINFO USER command (RFC 4643)
153  */
154 void nntp_authinfo_user(const char *username)
155 {
156         int a = CtdlLoginExistingUser(NULL, username);
157         switch (a) {
158         case login_already_logged_in:
159                 cprintf("482 Already logged in\r\n");
160                 return;
161         case login_too_many_users:
162                 cprintf("481 Too many users are already online (maximum is %d)\r\n", config.c_maxsessions);
163                 return;
164         case login_ok:
165                 cprintf("381 Password required for %s\r\n", CC->curr_user);
166                 return;
167         case login_not_found:
168                 cprintf("481 %s not found\r\n", username);
169                 return;
170         default:
171                 cprintf("502 Internal error\r\n");
172         }
173 }
174
175
176 /*
177  * Implements the AUTHINFO PASS command (RFC 4643)
178  */
179 void nntp_authinfo_pass(const char *buf)
180 {
181         int a;
182
183         a = CtdlTryPassword(buf, strlen(buf));
184
185         switch (a) {
186         case pass_already_logged_in:
187                 cprintf("482 Already logged in\r\n");
188                 return;
189         case pass_no_user:
190                 cprintf("482 Authentication commands issued out of sequence\r\n");
191                 return;
192         case pass_wrong_password:
193                 cprintf("481 Authentication failed\r\n");
194                 return;
195         case pass_ok:
196                 cprintf("281 Authentication accepted\r\n");
197                 return;
198         }
199 }
200
201
202
203 /*
204  * Implements the AUTHINFO extension (RFC 4643) in USER/PASS mode
205  */
206 void nntp_authinfo(const char *cmd) {
207
208         if (!strncasecmp(cmd, "authinfo user ", 14)) {
209                 nntp_authinfo_user(&cmd[14]);
210         }
211
212         else if (!strncasecmp(cmd, "authinfo pass ", 14)) {
213                 nntp_authinfo_pass(&cmd[14]);
214         }
215
216         else {
217                 cprintf("502 command unavailable\r\n");
218         }
219 }
220
221
222
223 /* 
224  * Main command loop for NNTP server sessions.
225  */
226 void nntp_command_loop(void)
227 {
228         StrBuf *Cmd = NewStrBuf();
229         char cmdname[16];
230
231         time(&CC->lastcmd);
232         if (CtdlClientGetLine(Cmd) < 1) {
233                 syslog(LOG_CRIT, "NNTP: client disconnected: ending session.\n");
234                 CC->kill_me = KILLME_CLIENT_DISCONNECTED;
235                 FreeStrBuf(&Cmd);
236                 return;
237         }
238         syslog(LOG_DEBUG, "NNTP server: %s\n", ChrPtr(Cmd));
239         extract_token(cmdname, ChrPtr(Cmd), 0, ' ', sizeof cmdname);
240
241         /*
242          * Rumpelstiltskin lookups are awesome
243          */
244
245         if (!strcasecmp(cmdname, "quit")) {
246                 nntp_quit();
247         }
248
249         else if (!strcasecmp(cmdname, "capabilities")) {
250                 nntp_capabilities();
251         }
252
253         else if (!strcasecmp(cmdname, "starttls")) {
254                 nntp_starttls();
255         }
256
257         else if (!strcasecmp(cmdname, "noop")) {
258                 nntp_noop();
259         }
260
261         else if (!strcasecmp(cmdname, "authinfo")) {
262                 nntp_authinfo(ChrPtr(Cmd));
263         }
264
265         else {
266                 cprintf("500 I'm afraid I can't do that.\r\n");
267         }
268
269         FreeStrBuf(&Cmd);
270 }
271
272
273 /*****************************************************************************/
274 /*                      MODULE INITIALIZATION STUFF                          */
275 /*****************************************************************************/
276
277
278 /*
279  * This cleanup function blows away the temporary memory used by
280  * the NNTP server.
281  */
282 void nntp_cleanup_function(void)
283 {
284         /* Don't do this stuff if this is not an NNTP session! */
285         if (CC->h_command_function != nntp_command_loop) return;
286
287         syslog(LOG_DEBUG, "Performing NNTP cleanup hook\n");
288 }
289
290 const char *CitadelServiceNNTP="NNTP";
291
292 CTDL_MODULE_INIT(nntp)
293 {
294         if (!threading)
295         {
296                 CtdlRegisterServiceHook(119,                    // FIXME config.c_nntp_port,
297                                         NULL,
298                                         nntp_greeting,
299                                         nntp_command_loop,
300                                         NULL, 
301                                         CitadelServiceNNTP);
302
303 #ifdef HAVE_OPENSSL
304                 CtdlRegisterServiceHook(563,                    // FIXME config.c_nntps_port,
305                                         NULL,
306                                         nntps_greeting,
307                                         nntp_command_loop,
308                                         NULL,
309                                         CitadelServiceNNTP);
310 #endif
311
312                 CtdlRegisterCleanupHook(nntp_cleanup);
313                 CtdlRegisterSessionHook(nntp_cleanup_function, EVT_STOP, PRIO_STOP + 250);
314         }
315         
316         /* return our module name for the log */
317         return "nntp";
318 }