1 /* nntpinit.c
2 */
3 /* This software is copyrighted as detailed in the LICENSE file. */
4 
5 
6 /*#define DECNET	*//* If you want decnet support */
7 /*#define EXCELAN	*//* Excelan EXOS 205 support */
8 /*#define NONETD	*//* Define if you're missing netdb.h */
9 
10 #include "EXTERN.h"
11 #include "common.h"
12 #include "nntpclient.h"
13 #include "INTERN.h"
14 #include "nntpinit.h"
15 #include "nntpinit.ih"
16 
17 #ifdef SUPPORT_NNTP
18 
19 #ifdef WINSOCK
20 #include <winsock.h>
21 WSADATA wsaData;
22 #else
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #ifdef NONETDB
26 # define IPPORT_NNTP	((unsigned short) 119)
27 #else
28 # include <netdb.h>
29 #endif
30 #endif
31 
32 #ifdef EXCELAN
33 int connect _((int, struct sockaddr*));
34 unsigned short htons _((unsigned short));
35 unsigned long rhost _((char**));
36 int rresvport p((int));
37 int socket _((int, struct sockproto *, struct sockaddr_in *, int));
38 #endif /* EXCELAN */
39 
40 #ifdef DECNET
41 #include <netdnet/dn.h>
42 #include <netdnet/dnetdb.h>
43 #endif /* DECNET */
44 
45 #ifndef WINSOCK
46 unsigned long inet_addr _((char*));
47 #ifndef NONETDB
48 struct servent* getservbyname();
49 struct hostent* gethostbyname();
50 #endif
51 #endif
52 
53 int
init_nntp()54 init_nntp()
55 {
56 #ifdef WINSOCK
57     if (WSAStartup(0x0101,&wsaData) == 0) {
58 	if (wsaData.wVersion == 0x0101)
59 	    return 1;
60 	WSACleanup();
61     }
62     fprintf(stderr,"Unable to initialize WinSock DLL.\n");
63     return -1;
64 #else
65     return 1;
66 #endif
67 }
68 
69 int
server_init(machine)70 server_init(machine)
71 char* machine;
72 {
73     int sockt_rd, sockt_wr;
74 #ifdef DECNET
75     char* cp;
76 #endif
77 
78 #ifdef DECNET
79     cp = index(machine, ':');
80 
81     if (cp && cp[1] == ':') {
82 	*cp = '\0';
83 	sockt_rd = get_dnet_socket(machine);
84     } else
85 	sockt_rd = get_tcp_socket(machine, nntplink.port_number, "nntp");
86 #else /* !DECNET */
87     sockt_rd = get_tcp_socket(machine, nntplink.port_number, "nntp");
88 #endif
89 
90     if (sockt_rd < 0)
91 	return -1;
92 
93     sockt_wr = dup(sockt_rd);
94 
95     /* Now we'll make file pointers (i.e., buffered I/O) out of
96     ** the socket file descriptor.  Note that we can't just
97     ** open a fp for reading and writing -- we have to open
98     ** up two separate fp's, one for reading, one for writing. */
99     if ((nntplink.rd_fp = fdopen(sockt_rd, "r")) == NULL) {
100 	perror("server_init: fdopen #1");
101 	return -1;
102     }
103     if ((nntplink.wr_fp = fdopen(sockt_wr, "w")) == NULL) {
104 	perror("server_init: fdopen #2");
105 	nntplink.rd_fp = NULL;
106 	return -1;
107     }
108 
109     /* Now get the server's signon message */
110     nntp_check();
111 
112     if (*ser_line == NNTP_CLASS_OK) {
113 	char save_line[NNTP_STRLEN];
114 	strcpy(save_line, ser_line);
115 	/* Try MODE READER just in case we're talking to innd.
116 	** If it is not an invalid command, use the new reply. */
117 	if (nntp_command("MODE READER") <= 0)
118 	    sprintf(ser_line, "%d failed to send MODE READER\n", NNTP_ACCESS_VAL);
119 	else if (nntp_check() <= 0 && atoi(ser_line) == NNTP_BAD_COMMAND_VAL)
120 	    strcpy(ser_line, save_line);
121     }
122     return atoi(ser_line);
123 }
124 
125 void
cleanup_nntp()126 cleanup_nntp()
127 {
128 #ifdef WINSOCK
129     WSACleanup();
130 #endif
131 }
132 
133 int
get_tcp_socket(machine,port,service)134 get_tcp_socket(machine, port, service)
135 char* machine;
136 int port;
137 char* service;
138 {
139     int s;
140 #if INET6
141     struct addrinfo hints;
142     struct addrinfo* res;
143     struct addrinfo* res0;
144     char portstr[8];
145     char* cause = NULL;
146     int error;
147 
148     memset(&hints, 0, sizeof hints);
149     hints.ai_family = PF_UNSPEC;
150     hints.ai_socktype = SOCK_STREAM;
151     hints.ai_flags = 0;
152     if (port)
153 	sprintf(service = portstr, "%d", port);
154     error = getaddrinfo(machine, service, &hints, &res0);
155     if (error) {
156 	fprintf(stderr, "%s", gai_strerror(error));
157 	return -1;
158     }
159     for (res = res0; res; res = res->ai_next) {
160 	char buf[64] = "";
161 	s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
162 	if (s < 0) {
163 	    cause = "socket";
164 	    continue;
165 	}
166 
167 	inet_ntop(res->ai_family, res->ai_addr, buf, sizeof buf);
168 	if (res != res0)
169 	    fprintf(stderr, "trying %s...", buf);
170 
171 	if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
172 	    break;  /* okay we got one */
173 
174 	fprintf(stderr, "connection to %s: ", buf);
175 	perror("");
176 	cause = "connect";
177 	close(s);
178 	s = -1;
179     }
180     if (s < 0) {
181 	fprintf(stderr, "giving up... ");
182 	perror(cause);
183     }
184     freeaddrinfo(res0);
185 #else	/* !INET6 */
186     struct sockaddr_in sin;
187 #ifdef __hpux
188     int socksize = 0;
189     int socksizelen = sizeof socksize;
190 #endif
191 #ifdef NONETDB
192     bzero((char*)&sin, sizeof sin);
193     sin.sin_family = AF_INET;
194 #else
195     struct hostent* hp;
196 #ifdef h_addr
197     int x = 0;
198     register char** cp;
199     static char* alist[1];
200 #endif /* h_addr */
201     static struct hostent def;
202     static struct in_addr defaddr;
203     static char namebuf[256];
204 
205     bzero((char*)&sin, sizeof sin);
206 
207     if (port)
208 	sin.sin_port = htons(port);
209     else {
210 	struct servent* sp;
211 	if ((sp = getservbyname(service, "tcp")) == NULL) {
212 	    fprintf(stderr, "%s/tcp: Unknown service.\n", service);
213 	    return -1;
214 	}
215 	sin.sin_port = sp->s_port;
216     }
217     /* If not a raw ip address, try nameserver */
218     if (!isdigit(*machine)
219 #ifdef INADDR_NONE
220      || (defaddr.s_addr = inet_addr(machine)) == INADDR_NONE)
221 #else
222      || (long)(defaddr.s_addr = inet_addr(machine)) == -1)
223 #endif
224 	hp = gethostbyname(machine);
225     else {
226 	/* Raw ip address, fake  */
227 	(void) strcpy(namebuf, machine);
228 	def.h_name = namebuf;
229 #ifdef h_addr
230 	def.h_addr_list = alist;
231 #endif
232 	def.h_addr = (char*)&defaddr;
233 	def.h_length = sizeof (struct in_addr);
234 	def.h_addrtype = AF_INET;
235 	def.h_aliases = 0;
236 	hp = &def;
237     }
238     if (hp == NULL) {
239 	fprintf(stderr, "%s: Unknown host.\n", machine);
240 	return -1;
241     }
242 
243     sin.sin_family = hp->h_addrtype;
244 #endif /* !NONETDB */
245 
246     /* The following is kinda gross.  The name server under 4.3
247     ** returns a list of addresses, each of which should be tried
248     ** in turn if the previous one fails.  However, 4.2 hostent
249     ** structure doesn't have this list of addresses.
250     ** Under 4.3, h_addr is a #define to h_addr_list[0].
251     ** We use this to figure out whether to include the NS specific
252     ** code... */
253 #ifdef h_addr
254     /* get a socket and initiate connection -- use multiple addresses */
255     for (cp = hp->h_addr_list; cp && *cp; cp++) {
256 	extern char* inet_ntoa _((const struct in_addr));
257 	s = socket(hp->h_addrtype, SOCK_STREAM, 0);
258 	if (s < 0) {
259 	    perror("socket");
260 	    return -1;
261 	}
262         bcopy(*cp, (char*)&sin.sin_addr, hp->h_length);
263 
264 	if (x < 0)
265 	    fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr));
266 	x = connect(s, (struct sockaddr*)&sin, sizeof (sin));
267 	if (x == 0)
268 	    break;
269         fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr));
270 	perror("");
271 	(void) close(s);
272     }
273     if (x < 0) {
274 	fprintf(stderr, "giving up...\n");
275 	return -1;
276     }
277 #else /* no name server */
278 #ifdef EXCELAN
279     s = socket(SOCK_STREAM, (struct sockproto*)NULL, &sin, SO_KEEPALIVE);
280     if (s < 0) {
281 	/* Get the socket */
282 	perror("socket");
283 	return -1;
284     }
285     bzero((char*)&sin, sizeof sin);
286     sin.sin_family = AF_INET;
287     sin.sin_port = htons(port? port : *service == 'n'? IPPORT_NNTP : 80);
288 
289     /* set up addr for the connect */
290     if ((sin.sin_addr.s_addr = rhost(&machine)) == -1) {
291 	fprintf(stderr, "%s: Unknown host.\n", machine);
292 	return -1;
293     }
294 
295     /* And then connect */
296     if (connect(s, (struct sockaddr*)&sin) < 0) {
297 	perror("connect");
298 	(void) close(s);
299 	return -1;
300     }
301 #else /* !EXCELAN */
302     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
303 	perror("socket");
304 	return -1;
305     }
306 
307     /* And then connect */
308 
309     bcopy(hp->h_addr, (char*)&sin.sin_addr, hp->h_length);
310     if (connect(s, (struct sockaddr*)&sin, sizeof sin) < 0) {
311 	perror("connect");
312 	(void) close(s);
313 	return -1;
314     }
315 
316 #endif /* !EXCELAN */
317 #endif /* !h_addr */
318 #endif /* !INET6 */
319 #ifdef __hpux	/* recommended by raj@cup.hp.com */
320 #define	HPSOCKSIZE 0x8000
321     getsockopt(s, SOL_SOCKET, SO_SNDBUF, (caddr_t)&socksize, (caddr_t)&socksizelen);
322     if (socksize < HPSOCKSIZE) {
323 	socksize = HPSOCKSIZE;
324 	setsockopt(s, SOL_SOCKET, SO_SNDBUF, (caddr_t)&socksize, sizeof (socksize));
325     }
326     socksize = 0;
327     socksizelen = sizeof (socksize);
328     getsockopt(s, SOL_SOCKET, SO_RCVBUF, (caddr_t)&socksize, (caddr_t)&socksizelen);
329     if (socksize < HPSOCKSIZE) {
330 	socksize = HPSOCKSIZE;
331 	setsockopt(s, SOL_SOCKET, SO_RCVBUF, (caddr_t)&socksize, sizeof (socksize));
332     }
333 #endif
334     return s;
335 }
336 
337 #ifdef DECNET
338 static int
get_dnet_socket(machine)339 get_dnet_socket(machine)
340 char* machine;
341 {
342     int s, area, node;
343     struct sockaddr_dn sdn;
344     struct nodeent *getnodebyname(), *np;
345 
346     bzero((char*)&sdn, sizeof sdn);
347 
348     switch (s = sscanf(machine, "%d%*[.]%d", &area, &node)) {
349     case 1:
350 	node = area;
351 	area = 0;
352     case 2:
353 	node += area*1024;
354 	sdn.sdn_add.a_len = 2;
355 	sdn.sdn_family = AF_DECnet;
356 	sdn.sdn_add.a_addr[0] = node % 256;
357 	sdn.sdn_add.a_addr[1] = node / 256;
358 	break;
359     default:
360 	if ((np = getnodebyname(machine)) == NULL) {
361 	    fprintf(stderr, "%s: Unknown host.\n", machine);
362 	    return -1;
363 	}
364 	bcopy(np->n_addr, (char*)sdn.sdn_add.a_addr, np->n_length);
365 	sdn.sdn_add.a_len = np->n_length;
366 	sdn.sdn_family = np->n_addrtype;
367 	break;
368     }
369     sdn.sdn_objnum = 0;
370     sdn.sdn_flags = 0;
371     sdn.sdn_objnamel = strlen("NNTP");
372     bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
373 
374     if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
375 	nerror("socket");
376 	return -1;
377     }
378 
379     /* And then connect */
380     if (connect(s, (struct sockaddr*)&sdn, sizeof sdn) < 0) {
381 	nerror("connect");
382 	close(s);
383 	return -1;
384     }
385     return s;
386 }
387 #endif /* DECNET */
388 
389 /*
390  * inet_addr for EXCELAN (which does not have it!)
391  */
392 #ifdef NONETDB
393 unsigned long
inet_addr(cp)394 inet_addr(cp)
395 register char* cp;
396 {
397     unsigned long val, base, n;
398     register char c;
399     unsigned long octet[4], *octetptr = octet;
400 #ifndef htonl
401     extern  unsigned long   htonl();
402 #endif  /* htonl */
403 again:
404     /* Collect number up to ``.''.
405      * Values are specified as for C:
406      * 0x=hex, 0=octal, other=decimal. */
407     val = 0; base = 10;
408     if (*cp == '0')
409 	base = 8, cp++;
410     if (*cp == 'x' || *cp == 'X')
411 	base = 16, cp++;
412     while (c = *cp) {
413 	if (isdigit(c)) {
414 	    val = (val * base) + (c - '0');
415 	    cp++;
416 	    continue;
417 	}
418 	if (base == 16 && isxdigit(c)) {
419 	    val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
420 	    cp++;
421 	    continue;
422 	}
423 	break;
424     }
425     if (*cp == '.') {
426 	/* Internet format:
427 	 *      a.b.c.d
428 	 *      a.b.c   (with c treated as 16-bits)
429 	 *      a.b     (with b treated as 24 bits) */
430 	if (octetptr >= octet + 4)
431 	    return -1;
432 	*octetptr++ = val, cp++;
433 	goto again;
434     }
435     /* Check for trailing characters. */
436     if (*cp && !isspace(*cp))
437 	return -1;
438     *octetptr++ = val;
439     /* Concoct the address according to the number of octet specified. */
440     n = octetptr - octet;
441     switch (n) {
442     case 1:    			/* a -- 32 bits */
443 	val = octet[0];
444 	break;
445     case 2:			/* a.b -- 8.24 bits */
446 	val = (octet[0] << 24) | (octet[1] & 0xffffff);
447 	break;
448     case 3:			/* a.b.c -- 8.8.16 bits */
449 	val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
450 	    (octet[2] & 0xffff);
451 	break;
452     case 4:			/* a.b.c.d -- 8.8.8.8 bits */
453 	val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
454 	    ((octet[2] & 0xff) << 8) | (octet[3] & 0xff);
455 	break;
456     default:
457 	return -1;
458     }
459     val = htonl(val);
460     return val;
461 }
462 #endif /* NONETDB */
463 
464 #endif /* SUPPORT_NNTP */
465