ftp.nice.ch/pub/next/unix/text/Webster.a5.s.tar.gz#/Webster/Daemon/daemon.c

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.