/* * SCCS: @(#)tccd_in.c 1.13 (98/09/01) * * UniSoft Ltd., London, England * * (C) Copyright 1992 X/Open Company Limited * (C) Copyright 1994 UniSoft Limited * * All rights reserved. No part of this source code may be reproduced, * stored in a retrieval system, or transmitted, in any form or by any * means, electronic, mechanical, photocopying, recording or otherwise, * except as stated in the end-user licence agreement, without the prior * permission of the copyright owners. * * X/Open and the 'X' symbol are trademarks of X/Open Company Limited in * the UK and other countries. */ #ifdef HAVE_CONFIG_H #include #endif /************************************************************************ SCCS: @(#)tccd_in.c 1.13 98/09/01 TETware release 3.3 NAME: tccd_in.c PRODUCT: TETware AUTHOR: Andrew Dingwall, UniSoft Ltd. DATE CREATED: April 1992 DESCRIPTION: server-specific functions for tccd INET version MODIFICATIONS: Andrew Dingwall, UniSoft Ltd., November 1993 enhancements for FIFO transport interface Andrew Dingwall, UniSoft Ltd., February 1995 clear sockaddr_in before using it Geoff Clare, UniSoft Ltd., August 1996 Missing . Andrew Dingwall, UniSoft Ltd., March 1997 remove #ifndef __hpux from #include since current HP-UX implementations now have this file Andrew Dingwall, UniSoft Ltd., July 1998 Added support for shared API libraries. Changes to conform to UNIX98. Aaron Plattner, April 2010 Fixed warnings when compiled with GCC's -Wall option. ************************************************************************/ #include #include #include #include #include # include # include # include # include # include # include # ifndef INETD # include # include # endif /* !INETD */ #include "dtmac.h" #include "dtmsg.h" #include "ptab.h" #include "tptab_in.h" #include "tsinfo_in.h" #include "error.h" #include "globals.h" #include "ltoa.h" #include "tccd.h" #include "tccd_bs.h" #include "bstring.h" #include "server.h" #include "server_in.h" #include "inetlib_in.h" #include "servlib.h" #include "dtetlib.h" /* only the INETD version on supported on WIN32 platforms */ static char rhostname[256]; /* remote host name */ #ifdef INETD SOCKET tet_listen_sd = INVALID_SOCKET; /* inetd listens on the socket for us */ #else SOCKET tet_listen_sd; /* socket on which to listen */ int Tccdport = 0; /* tccd well-known port number */ #endif /* static function declarations */ #ifndef INETD static SIG_FUNC_T waitchild PROTOLIST((int)); #endif /* !INETD */ /* ** ss_tsargproc() - transport-specific tccd command-line argument ** processing ** ** return 0 if only firstarg was used or 1 if both args were used */ #ifdef INETD /* ARGSUSED */ #endif int ss_tsargproc(firstarg, nextarg) char *firstarg, *nextarg; { register int rc = 0; switch (*(firstarg + 1)) { #ifndef INETD case 'p': if (*(firstarg + 2)) Tccdport = atoi(firstarg + 2); else { Tccdport = atoi(nextarg); rc = 1; } if (Tccdport <= 0) fatal(0, "bad port number:", rc == 1 ? nextarg : firstarg + 2); break; #endif /* !INETD */ default: fatal(0, "unknown option", firstarg); /* NOTREACHED */ } return(rc); } /* ** ss_tsinitb4fork() - tccd INET initialisation before forking a daemon */ void ss_tsinitb4fork() { #ifdef INETD register struct ptab *pp; register struct tptab *tp; register SOCKET sd; int len; /* move the incoming request socket off stdin */ errno = 0; if ((sd = fcntl(0, F_DUPFD, 3)) < 3) fatal(errno, "can't dup stdin socket", (char *) 0); close(0); /* allocate a ptab entry for the incoming request */ if ((pp = tet_ptalloc()) == (struct ptab *) 0) exit(1); tp = (struct tptab *) pp->pt_tdata; tp->tp_sd = sd; /* get remote address and store it */ len = sizeof tp->tp_sin; if (getpeername(tp->tp_sd, (struct sockaddr *) &tp->tp_sin, &len) == SOCKET_ERROR) fatal(SOCKET_ERRNO, "can't get name of connected peer", (char *) 0); /* log the connection */ tet_ss_tsafteraccept(pp); /* register the ptab entry */ tet_ss_newptab(pp); /* prepare to receive the message */ pp->pt_state = PS_RCVMSG; pp->pt_flags |= PF_ATTENTION; #else /* INETD */ struct sockaddr_in sin; register int sd; SIG_FUNC_T waitchild(); /* get the tccd port number if not overridden on the cmd line */ bzero((char *) &sin, sizeof sin); if (Tccdport <= 0 && (Tccdport = tet_gettccdport()) < 0) exit(1); else sin.sin_port = htons((unsigned short) Tccdport); /* get a socket to listen on */ if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) fatal(errno, "can't create listen socket", (char *) 0); /* make sure that listen socket is not stdin, stdout or stderr */ if (sd < 3) { errno = 0; if ((tet_listen_sd = fcntl(sd, F_DUPFD, 3)) < 3) fatal(errno, "can't dup listen socket", (char *) 0); close(sd); } else tet_listen_sd = sd; /* bind the socket to the tccd port */ sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; if (bind(tet_listen_sd, (struct sockaddr *) &sin, sizeof sin) < 0) fatal(errno, "can't bind to listen socket", (char *) 0); /* arrange to accept incoming connections */ tet_ts_listen(tet_listen_sd); /* arrange to reap child daemon processes */ signal(SIGCHLD, waitchild); #endif /* INETD */ } /* ** ts_forkdaemon() - start a daemon process */ #ifndef INITTAB void ts_forkdaemon() { #ifdef INETD /* inetd has already done it for us */ #else /* INETD */ tet_si_forkdaemon(); #endif /* INETD */ } #endif /* !INITTAB */ /* ** ts_logstart() - make a log file entry when the master daemon starts */ void ts_logstart() { #ifdef INETD /* no master daemon */ #else logent("START", (char *) 0); #endif } /* ** tet_ss_tsconnect() - server-specific connect processing ** ** return 0 if successful or -1 on error */ int tet_ss_tsconnect(pp) struct ptab *pp; { /* syncd and xresd addresses have alread been stored when op_tsinfo() was called (which also allocated the ptabs) - if this had not happened, we would not have got past tet_ti_logon() */ switch (pp->ptr_ptype) { case PT_SYNCD: case PT_XRESD: return(0); } error(0, "don't know how to connect to", tet_ptptype(pp->ptr_ptype)); return(-1); } /* ** tet_ss_tsaccept() - server-specific accept() processing */ void tet_ss_tsaccept() { #ifdef INETD /* inetd has already accepted the connection */ #else /* accept the connection unless we are closing down */ if (tet_listen_sd != INVALID_SOCKET) tet_ts_accept(tet_listen_sd); #endif } /* ** tet_ss_tsafteraccept() - server-specific things to do after an accept() ** ** return 0 if successful or -1 on error */ int tet_ss_tsafteraccept(pp) struct ptab *pp; { register struct tptab *tp = (struct tptab *) pp->pt_tdata; register struct hostent *hp; register char *p; #ifndef INETD register int pid; #endif /* log the connection */ if ((hp = gethostbyaddr((char *) &tp->tp_sin.sin_addr, sizeof tp->tp_sin.sin_addr, tp->tp_sin.sin_family)) != (struct hostent *) 0) p = hp->h_name; else p = inet_ntoa(tp->tp_sin.sin_addr); sprintf(rhostname, "%.*s", (int) sizeof rhostname - 1, p); logent("connection received from", rhostname); #ifdef INETD /* inetd does the accept for us */ pp->pt_flags |= PF_CONNECTED; #else if ((pid = tet_dofork()) < 0) { error(errno, "can't fork", (char *) 0); return(-1); } else if (!pid) { /* in child */ tet_mypid = getpid(); close(tet_listen_sd); tet_listen_sd = INVALID_SOCKET; signal(SIGCHLD, SIG_DFL); } else { /* in parent - return -1 to close the socket and free the ptab entry */ return(-1); } #endif /* INETD */ return(0); } /* ** ss_tslogon() - make sure that we want to accept a logon request ** from the connected remote host ** ** return ER_OK if successful or other ER_* error code on error */ int ss_tslogon() { static char equiv[] = "systems.equiv"; char fname[MAXPATH + 1]; char *argv[1]; register int argc, rc; register unsigned long raddr; FILE *fp; ASSERT(tet_root[0]); sprintf(fname, "%.*s/%s", (int) sizeof fname - (int) sizeof equiv - 1, tet_root, equiv); /* open the systems.equiv file */ if ((fp = fopen(fname, "r")) == NULL) { error(errno, "can't open", fname); return(ER_ERR); } /* look for the requesting system in the systems.equiv file */ raddr = inet_addr(rhostname); rc = ER_ERR; while ((argc = tet_fgetargs(fp, argv, 1)) != EOF) if (argc < 1) continue; else if ((raddr == -1 && strcmp(argv[0], rhostname) == 0) || inet_addr(argv[0]) == raddr) { rc = ER_OK; break; } if (rc != ER_OK) error(0, "refused login request from", rhostname); fclose(fp); return(rc); } /* ** waitchild() - reap a child daemon */ #ifdef INETD /* no daemon children to wait for */ #else /* ARGSUSED */ static SIG_FUNC_T waitchild(sig) int sig; { int status; #ifndef NOTRACE register int pid; #endif signal(SIGCHLD, SIG_DFL); #ifdef NOTRACE while (tet_dowait3(&status, WNOHANG) > 0) ; #else while ((pid = tet_dowait3(&status, WNOHANG)) > 0) TRACE4(tet_Ttccd, 2, "waitchild reaped %s, status %s, signal %s", tet_i2a(pid), tet_i2a((status >> 8) & 0xff), tet_i2a(status & 0xff)); #endif signal(SIGCHLD, waitchild); } #endif /* ** ts_bs2tsinfo() - call tet_bs2tsinfo() */ int ts_bs2tsinfo(from, fromlen, to, tolen) char *from; int fromlen; char **to; int *tolen; { return(tet_bs2tsinfo(from, fromlen, (struct tsinfo **) to, tolen)); } /* ** op_tsinfo() - receive transport-specific data */ void op_tsinfo(pp) register struct ptab *pp; { register struct tsinfo *mp = (struct tsinfo *) pp->ptm_data; register struct sockaddr_in *ap; /* all reply messages have no data */ pp->ptm_mtype = MT_NODATA; pp->ptm_len = 0; /* decide where to store the data; allocate a ptab entry for the server if necessary */ switch (mp->ts_ptype) { case PT_SYNCD: if (!tet_sdptab) { if ((tet_sdptab = tet_ptalloc()) == (struct ptab *) 0) { pp->ptm_rc = ER_ERR; return; } tet_sdptab->ptr_sysid = 0; tet_sdptab->ptr_ptype = PT_SYNCD; tet_sdptab->pt_flags = PF_SERVER; } ap = &((struct tptab *) tet_sdptab->pt_tdata)->tp_sin; break; case PT_XRESD: if (!tet_xdptab) { if ((tet_xdptab = tet_ptalloc()) == (struct ptab *) 0) { pp->ptm_rc = ER_ERR; return; } tet_xdptab->ptr_sysid = 0; tet_xdptab->ptr_ptype = PT_XRESD; tet_xdptab->pt_flags = PF_SERVER; } ap = &((struct tptab *) tet_xdptab->pt_tdata)->tp_sin; break; default: error(0, "received tsinfo for unexpected ptype", tet_ptptype(mp->ts_ptype)); pp->ptm_rc = ER_ERR; return; } /* store the data */ ap->sin_family = AF_INET; ap->sin_addr.s_addr = htonl(mp->ts_addr); ap->sin_port = htons(mp->ts_port); TRACE4(tet_Ttccd, 2, "received tsinfo for %s: addr = %s, port = %s", tet_ptptype(mp->ts_ptype), inet_ntoa(ap->sin_addr), tet_i2a(ntohs(ap->sin_port))); /* all ok so set up the reply message and return */ pp->ptm_rc = ER_OK; }