This is daemon.c in view mode; [Download] [Up]
/* Webster Access, a program to use NeXT online Webster dictionary. Copyright (C) 1994 Benoit Grange, ben@fizz.fdn.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #import <stdio.h> #import <stdlib.h> #import <libc.h> #import <sys/types.h> #import <errno.h> #import <strings.h> #import <memory.h> #import <sys/socket.h> #import <sys/socketvar.h> #import <netinet/in.h> #import <arpa/inet.h> #import <netdb.h> #include <syslog.h> #import "daemon.h" #import "commands.h" #import "config.h" const char* pgmname; // Used to run the connection struct sockaddr_in remoteAddress; int remoteAddressLength = sizeof(remoteAddress); int cx; FILE *clientR = NULL; FILE *clientW = NULL; void report() { struct rusage usage; getrusage(RUSAGE_SELF, &usage); syslog(LOG_INFO, "CPU time = %lg ms\n", ((double)usage.ru_utime.tv_sec + (double)usage.ru_stime.tv_sec) * 1000.0 + ((double)usage.ru_utime.tv_usec + (double)usage.ru_stime.tv_usec) / 1000.0); } void runCx(void) { struct hostent *h1 = NULL, *h2 = NULL; if (!(clientR = fdopen(cx, "r"))) perror("fdopen"), exit(1); if (!(clientW = fdopen(cx, "a"))) perror("fdopen"), exit(1); if (remoteAddressLength != sizeof(remoteAddress)) { syslog(LOG_ERR, "socket address is too short (%d < %lu)\n", remoteAddressLength, sizeof(remoteAddress)); exit(1); } /* Double check, find name from address, and check that address is one of the listed one for this address. This will prevent NS spoofing */ h1 = gethostbyaddr((void *)&remoteAddress.sin_addr, sizeof(remoteAddress.sin_addr), AF_INET); if (h1) h2 = gethostbyname(h1->h_name); if (h2) { // h1 is name from address, ununsed later // h2 is name & addresse(s) from name // check that h2 lists the remoteAddress long **hlist = (long **)h2->h_addr_list; while (**hlist != 0) { if (**hlist == (long)remoteAddress.sin_addr.S_un.S_addr) break; hlist++; } if (**hlist == 0) { syslog(LOG_NOTICE, "Address %s maps to host '%s', this maps to '%s', " "but %s is not listed in its adresses (DNS spoofing suspected)", inet_ntoa(remoteAddress.sin_addr), h1?h1->h_name:"unknown host", h2?h2->h_name:"unknown host", inet_ntoa(remoteAddress.sin_addr) ); h2 = NULL; } } if (requirements & hostname && !h2) goto fail; /* Check that cx is allowed, no requirements -> allow all */ if (allowedList) { allow *a = allowedList; while (a) { if (a->domain && h2) { if ((strlen(h2->h_name) >= strlen(a->domain)) && !strcmp(a->domain, h2->h_name + strlen(h2->h_name) - strlen(a->domain))) break; } else { if ((remoteAddress.sin_addr.s_addr & a->mask) == a->addr) break; } a = a->next; } if (!a) goto fail; } syslog(LOG_INFO, "accepted connection from %s (%s)\n", h2?h2->h_name:"unknown host", inet_ntoa(remoteAddress.sin_addr)); // fprintf(clientW, "200 %s\n", // greetingText?greetingText:"Connected"); fflush(clientW); commandLoop(); report(); return; fail: syslog(LOG_NOTICE, "refused connection from %s (%s)\n", h2?h2->h_name:"unknown host", inet_ntoa(remoteAddress.sin_addr)); fprintf(clientW, "529 You are not allowed to use this service\n"); fflush(clientW); fclose(clientR); fclose(clientW); exit(1); } void waitCx(int port) /* Create a socket, listen, and process ONE connection */ { int listener, on = 1; struct sockaddr_in localAddress; int localAddressLength = sizeof(localAddress); if ((listener = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))<0) perror("socket"), exit(1); if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))<0) perror("setsockopt SO_REUSEADDR"), exit(1); localAddress.sin_family = AF_INET; localAddress.sin_port = htons(port); localAddress.sin_addr.s_addr = 0; /* Unbound */ if (bind(listener, (struct sockaddr *)&localAddress, localAddressLength)<0) syslog(LOG_ERR, "bind(): %m"), exit(1); if (listen(listener, 1)<0) syslog(LOG_ERR, "listen(): %m"), exit(1); remoteAddressLength = sizeof(remoteAddress); if ((cx = accept(listener, (struct sockaddr *)&remoteAddress, &remoteAddressLength))<0) syslog(LOG_ERR, "accept(): %m"), exit(1); if (close(listener)<0) syslog(LOG_ERR, "close(): %m"), exit(1); runCx(); report(); } int main(int argc, char **argv) { pgmname = *argv; argv++; argc--; readConfig(NULL); openlog("websterd", LOG_PID, logFacility); if (*argv && !strcmp(*argv, "-")) { syslog(LOG_DEBUG, "Started (stdin)"); cx = 0; if (!(clientR = fdopen(0, "rb"))) perror("fdopen"), exit(1); if (!(clientW = fdopen(1, "ab"))) perror("fdopen"), exit(1); fprintf(clientW, "211%cConnected to standard input\n", (greetingText)?'-':' '); if (greetingText) fprintf(clientW, "211 %s\n", greetingText); commandLoop(); fclose(clientW); fclose(clientR); exit(0); } /* Testing if launched by inetd, if this is the case, file 0 is a socket */ if (getpeername(0, (struct sockaddr *)&remoteAddress, &remoteAddressLength)<0) { if (errno != ENOTSOCK) syslog(LOG_ERR, "getpeername(0,...): %m"), exit(1); waitCx(tcpPort); } else { cx = 0; runCx(); } fclose(clientW); fclose(clientR); return(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.