/* ***************************************************************************** * * Copyright 1989, Xylogics, Inc. ALL RIGHTS RESERVED. * * ALL RIGHTS RESERVED. Licensed Material - Property of Xylogics, Inc. * This software is made available solely pursuant to the terms of a * software license agreement which governs its use. * Unauthorized duplication, distribution or sale are strictly prohibited. * * Module Function: * * ERPC listener process * * Original Author: Jonathan Taylor Created on: 84/08/07 * ***************************************************************************** */ /* * Include Files */ #include "../inc/port/install_dir.h" #include "../inc/vers.h" #include "../inc/config.h" #include "../inc/port/port.h" #include #include "../libannex/api_if.h" #include #include #ifndef _WIN32 #include #include #include #include #include #else #include #include #endif #include #include #include #include #include "../libannex/srpc.h" #include "../inc/courier/courier.h" #include "../inc/erpc/erpc.h" #include "../inc/erpc/nerpcd.h" #include "acp_policy.h" #include "getacpuser.h" #ifndef _WIN32 #define USE_CLIENT_REC #include "acp.h" #include "acp_group.h" #include "acp_lib.h" #include "environment.h" #include "time_parser.h" #endif #include "acp_regime.h" #ifdef _WIN32 #include "../inc/rom/syslog.h" #else #include #endif /* _WIN32 */ /* * External Data Declarations */ char group_file[PATHSZ]; char regime_file[PATHSZ]; int deny_all_users = TRUE; /* If TRUE, deny access to all users. * when acp_userinfo is parsed successfully, * this is reset to FALSE. */ #ifdef DEBUG_TO_FILE FILE *dbgout = NULL; #endif /* * Defines and Macros */ #define STDIN 0 #define STDOUT 1 #define STDERR 2 #define BUFFSIZE 2048 #define ERPC_CHILD_MAX 25 /* maximum number of forked processes */ #define SESNUMANNEX_DEFAULT 250 /* number of annexes supported by radius */ #define COURRPN_ACP 3 #define LISTEN_BACKLOG 5 /* maximum for tcp listen queue */ #define DEF_LINGER_TIME 120 #ifndef _WIN32 #ifndef SIGCHLD #ifndef SIGCLD error: no SIGCLD/SIGCHLD ! #else #define SIGCHLD SIGCLD #endif #endif #endif #ifndef _WIN32 struct clientrec clientrec[ERPC_CHILD_MAX]; #endif #ifndef BFS #define BFS "/usr/spool/erpcd/bfs" #endif #ifndef INSTALL_DIR #define INSTALL_DIR "/etc" #endif /* ACP Enhancements */ #ifdef MAX_BL_CON int maxcon = MAX_BL_CON; #else int maxcon = -1; #endif #ifdef MAX_BL_NONCON int maxtotal = MAX_BL_NONCON; #else int maxtotal = -1; #endif #ifdef MAX_BL_PERIOD time_t period = (time_t)(7 * 60 * 60 * MAX_BL_PERIOD); #else time_t period = 0; #endif #ifndef MAX_FAILURES #define MAX_FAILURES 20 #endif /* * Structure Definitions */ struct eservent { u_short es_rpnum; u_short es_verlo, es_verhi; char *es_name; }; /* * Forward Routine Declarations */ StructErpcdOption *ErpcdOpt; char command_line[256]; #ifdef ORACLE extern char ora_user[ACP_MAXLSTRING]; #endif #ifdef _WIN32 char szDefaultDomain[20]; char InstallDirBuf[256], RootDirBuf[256]; extern StructRadiusOption *RadiusOpt; extern int radius_server_count; int pcount; HANDLE hEventSIGCHLD; HANDLE hEventSIGHUP; HANDLE hEventSIGPWR; HANDLE hEventContinue; HANDLE hEventStop; HANDLE hEventOKToExitUDP; HANDLE hEventOKToExitTCP; HANDLE hSemaphoreChildCount; HANDLE hMapStructErpcdOption; HANDLE hMapStructRadiusOption; HANDLE hThreadSIGHUP; HANDLE hThreadSIGPWR; HANDLE hThreadUpdate; HANDLE hThreadServiceStop; DWORD dwThreadID; BOOL Inherit; void ServiceControlStop(void *); void UpdateErpcdOpt(void *); void ReadRegistryParam(); void sdump(); int syslog( int pri, const char *format, ...); BOOL InitAlarmThread(void); BOOL GetPrimaryDomainName(int); void random_seed(char *seed); void clear_user_profile(void); void hangup(void *), leave_erpcd(void *); #else /* _WIN32 */ StructErpcdOption StructErpcdOptionBlock; void reaper(); void re_acpuser(); void koolaidfest(); void acpuser(); int suicide(); void hangup(), leave_erpcd(); #endif /* _WIN32 */ struct eservent *geteservent(), *geteservbynum(); int erpcd_kid(); int open_user_profile_file(); int close_user_profile_file(); int initialize_user_profile_file(); int api_open(); int api_bind(); int api_connect(); int api_recv(); int api_recvmsg(); int api_sendmsg (); int api_send(); int api_rcvud(); int api_sndud(); int api_release(); int api_close(); int api_opt(); int bfs(); int acp(); void erpc_reject(); void secure_cache(); void seteservent(); void acp_tcp(); int api_listen(); int api_accept(); void display(); void acpuser (); UINT32 get_long(); void erpcd_init(); void endeservent(); static void udp_accept(); static void tcp_accept(); /* * Global Data Declarations */ #define ERPCD 1 /* Needed for xyreg.c. This files * need to know if they are running as part of the * erpcd daemon or standalone in install.dll. If this * constant is undefined, then it will define its own * version of the next variable "debug". If this * constant is defined it will look externally for * "debug". Externally meaning in this file. */ int debug = 0; /* 1 iff called with -d; 0 otherwise */ struct in_addr myipaddr; time_t erpcd_boottime; /* Ensure long-word alignment for ICL SPARC machines. */ INT32 cbuff[(BUFFSIZE+sizeof(INT32)-1)/sizeof(INT32)]; char *install_dir = INSTALL_DIR; char *root_dir = BFS; Radius_server *default_servers = NULL; /* acp_regime.h */ #ifndef _WIN32 Radius_serverinfo *radius_head = NULL; /* acp_regime.h */ int raddb_numannex = SESNUMANNEX_DEFAULT; int raddb_up = FALSE; extern int ses_open_db(); #else /* WIN32 */ /* ---------------------------------------------- This variable must only be changed under control of UseCriticalSection() */ CRITICAL_SECTION GlobalCriticalSection; Radius_serverinfo *radius_head = NULL; /* ---------------------------------------------- */ #endif /* WIN32 */ char eservices_name[256], userinfo_name[256]; /* * Static Declarations */ /* current number and max number of forked processes, used in main() and reaper() */ int child_count = 0; /* made global for version request */ int child_max = ERPC_CHILD_MAX; /* ibid */ int child_rejects = 0; /* number of rejects due to max */ static int use_udp = TRUE; static int use_tcp = TRUE; static struct sockaddr_in tcpaddr, udpaddr, from; static int api_options = 0; int tcpsock, udpsock; static int showpid = 0; char *myname = NULL; int udp_child = FALSE; static void usage() { #ifdef ORACLE fprintf(stdout,"Usage:\ \n\terpcd [-f] [-s] [-d[]] [-D[#]]\ \n\t\t[-c] [-u [filename]] [-b] [-x] \ \n\t\t[-g] [-[l,L]] [-[a,A]] [-n] [-[t,T]] [-v] [-R] \ \n\t\t[-O ] \ \n"); fprintf(stdout,"Where:\ \n\t-f\tBoot file directory.\n\t-s\tSecurity directory.\ \n\t-d\tPort number or name.\n\t-D\tDebug mode with level.\ \n\t-c\tMaximum number of child processes.\ \n\t-u\tVerify user profile (acp_userinfo) syntax.\ \n\t-b\tMaximum consecutive login failures before blacklisting.\ \n\t-x\tMaximum nonconsecutive login failures before blacklisting.\ \n\t-g\tTime period for nonconsecutive login failures.\ \n\t-lL\tACP logfile information directed to syslog. \n\t\t-l turns it off, -L turns it on.\ \n\t-aA\tACP logfile, -a turns it off, -A turns it on.\ \n\t-n\tUse host name instead of IP Address in logfile.\ \n\t-O\tUsername and Password for database access.\ \n\t-tT\tACP log information stamped with date/second, \n\t\t-t use seconds, -T use standard time format.\ \n\t-v\tDisplay software version number.\ \n\t-R\tMaximum number of Annexes in RADIUS table.\n"); ErpcdExit(1); #endif #ifndef _WIN32 fprintf(stdout,"Usage:\ \n\terpcd [-f] [-s] [-d[]] [-D[#]]\ \n\t\t[-c] [-u [filename]] [-b] [-x] \ \n\t\t[-g] [-[l,L]] [-[a,A]] [-n] [-[t,T]] [-v] [-R] \ \n"); fprintf(stdout,"Where:\ \n\t-f\tBoot file directory.\n\t-s\tSecurity directory.\ \n\t-d\tPort number or name.\n\t-D\tDebug mode with level.\ \n\t-c\tMaximum number of child processes.\ \n\t-u\tVerify user profile (acp_userinfo) syntax.\ \n\t-b\tMaximum consecutive login failures before blacklisting.\ \n\t-x\tMaximum nonconsecutive login failures before blacklisting.\ \n\t-g\tTime period for nonconsecutive login failures.\ \n\t-lL\tACP logfile information directed to syslog. \n\t\t-l turns it off, -L turns it on.\ \n\t-aA\tACP logfile, -a turns it off, -A turns it on.\ \n\t-n\tUse host name instead of IP Address in logfile.\ \n\t-tT\tACP log information stamped with date/second, \n\t\t-t use seconds, -T use standard time format.\ \n\t-v\tDisplay software version number.\ \n\t-R\tMaximum number of Annexes in RADIUS table.\n"); #else fprintf(stdout,"Usage:\ \n\terpcd [-d[]] [-D[#]] [-c] [-u [filename]] \n"); fprintf(stdout,"Where:\ \n\t-d\tPort number or name.\ \n\t-D\tDebug mode with level.\ \n\t-c\tMaximum number of children.\ \n\t-u\tVerify user profile (acp_userinfo) syntax.\n"); #endif ErpcdExit(1); } #define DO_EXTRA_PARM(FUNC) \ if (cp[1] == '\0') { \ if (--argc <= 0 || (cp = *++argv) == NULL) \ FUNC; \ } else \ cp++ #define OPTIONAL_EXTRA_PARM DO_EXTRA_PARM(break) #define EXTRA_OR_NULL DO_EXTRA_PARM(cp = NULL) #define EXTRA_PARM DO_EXTRA_PARM(goto show_usage) static void handle_arguments(argc,argv) int argc; char **argv; { char *cp; #ifndef _WIN32 /* not used in win32 */ char rangebuf[20]; int buf; #endif int i; char *portname = "erpc"; struct stat sbuf; struct servent *sp; unsigned mode = M_LINT; bzero(&tcpaddr, sizeof(struct sockaddr_in)); bzero(&udpaddr, sizeof(struct sockaddr_in)); /* get command line */ command_line[0]=0; for (i=0; iUseSyslog = TRUE; #else ErpcdOpt->UseSyslog = FALSE; #endif /* USE_SYSLOG */ #ifdef USE_LOGFILE ErpcdOpt->UseLogfile = TRUE; #else ErpcdOpt->UseLogfile = FALSE; #endif /* USE_LOGFILE */ #else ErpcdOpt->UseSyslog = FALSE; ErpcdOpt->UseLogfile = TRUE; #endif /* Win32 */ ErpcdOpt->UseHostName = FALSE; /* default use IP address in logfile */ ErpcdOpt->UseSeconds = FALSE; /* default use seconds format in ACP log */ ErpcdOpt->UseGroupAuthentication = FALSE; /* default use seconds format in ACP log */ #endif while (--argc > 0 && (cp = *++argv) != NULL) { if (cp[0] == '-' && cp[1] != '\0') switch (*++cp) { #ifdef _WIN32 case '#': /* ERPCD process count */ pcount = atoi(cp+1); break; #endif #ifdef USE_NDBM /* ACP Enhancements */ case 'b': maxcon = atoi(cp+1); if(maxcon < 0){ maxcon = -1; fprintf(stdout, ERPCD_RANGE, "-b", "0+"); } break; case 'x': maxtotal = atoi(cp + 1); if(maxtotal < 0 || (maxtotal > MAX_FAILURES)){ sprintf(rangebuf, "0-%d", MAX_FAILURES); fprintf(stdout, ERPCD_RANGE, "-x", rangebuf); maxtotal = -1; } break; case 'g': buf = atoi(cp + 1); period = (time_t)7 * 3600 * buf; if(buf <=0){ fprintf(stdout, ERPCD_RANGE, "-g", "0+"); period = 0; } break; #endif case '1': /* Turn off use_udp */ use_udp = FALSE; break; case '2': /* Turn off use_tcp */ use_tcp = FALSE; break; #ifndef _WIN32 case 'a': /* Turn off acp_logfile */ ErpcdOpt->UseLogfile = FALSE; break; case 'A': /* Turn on acp_logfile */ ErpcdOpt->UseLogfile = TRUE; break; case 'l': /* Turn off syslog */ ErpcdOpt->UseSyslog = FALSE; break; case 'L': /* Turn on syslog */ ErpcdOpt->UseSyslog = TRUE; break; case 'n': /* Use host name */ ErpcdOpt->UseHostName = TRUE; break; case 't': /* Use seconds */ ErpcdOpt->UseSeconds = TRUE; break; case 'T': /* Use standard time format */ ErpcdOpt->UseSeconds = FALSE; break; case 'f': /* File (BFS) directory */ EXTRA_PARM; if (stat(cp,&sbuf) < 0) perror(cp); else if ((sbuf.st_mode&S_IFMT)!=S_IFDIR) fprintf(stdout, "Bad file mode: %s: %o.\n", cp,sbuf.st_mode); else { root_dir = cp; break; } ErpcdExit(1); case 's': /* Security (ACP) directory */ EXTRA_PARM; if (stat(cp,&sbuf) < 0) perror(cp); else if ((sbuf.st_mode&S_IFMT)!=S_IFDIR) fprintf(stdout, "Bad file mode: %s: %o.\n", cp,sbuf.st_mode); else { install_dir = cp; break; } ErpcdExit(1); case 'R': /* RADIUS Session records */ raddb_numannex = atoi(cp+1); if (raddb_numannex < 8) raddb_numannex = SESNUMANNEX_DEFAULT; break; #endif /* WIN32 */ case 'd': /* API debug & ERPC port */ api_options |= API_TO_DEBUG; OPTIONAL_EXTRA_PARM; portname = cp; break; case 'D': /* ERPCD debug level */ debug = atoi(cp+1); if (debug <= 0) debug = 1; fprintf(stdout, "erpcd: debug level %d\n", debug); break; case 'p': showpid = 1; break; case 'U': /* Syntax check for ERPCD developers (undocumented) */ mode |= M_DEBUG; case 'u': /* Syntax check */ EXTRA_OR_NULL; if (cp == NULL || stat(cp, &sbuf) == 0) { open_user_profile_file(cp); initialize_user_profile_file(mode); close_user_profile_file(); #ifndef _WIN32 ACP_REGIME(regime_file); if (validate_acp_regime_file() == FALSE) { fprintf(stdout, "erpcd: regime_file %s failed validation\n", regime_file); ErpcdExit(1); } #endif } else perror(cp); ErpcdExit(0); case 'v': printf("erpcd host tool version %s, released %s\n", VERSION,RELDATE); ErpcdExit(0); case 'c': EXTRA_PARM; child_max = atoi(cp); if (child_max <= 0) child_max = ERPC_CHILD_MAX; break; #ifdef ORACLE case 'O': EXTRA_PARM; strcpy (ora_user, cp); break; #endif default: fprintf(stdout,"Unknown switch: -%c\n", *cp); show_usage: usage(); } else { if (strcmp(cp,"help") != 0) fprintf(stdout, "Illegal argument: \"%s\"\n", cp); usage(); } } if (period <= 0) /* if no period, then disable bl on total failures */ maxtotal = -1; sp = getservbyname(portname,"udp"); if (sp != NULL) udpaddr.sin_port = sp->s_port; else if (isdigit(*portname)) { int portnum; portnum = atoi(portname); if (portnum <= 0 || portnum > 65535) { fprintf(stdout, "erpcd: Illegal port number -- \"%s\"\n", portname); ErpcdExit(1); } udpaddr.sin_port = htons((u_short)portnum); } else { fprintf(stdout, "erpcd: Warning: unknown service udp/%s\n", portname); udpaddr.sin_port = htons((u_short)121); } sp = getservbyname(portname,"tcp"); if (sp != NULL) tcpaddr.sin_port = sp->s_port; else tcpaddr.sin_port = udpaddr.sin_port; } void declare_self(newsock) int newsock; { char *bp; PROBE response; int length, rv; bzero(&response, sizeof(PROBE)); response.head.pid = 0; /* htonl(getpid()); */ response.head.client = htons(PET_AREPLY); response.head.devclass = htons(DC_LOGHOST | DC_AUTHHOST | DC_BOOTHOST); response.head.pcode = htonl(PC_HOST); response.version[0] = 100; response.version[1] = 0; response.version[2] = 5; response.af = htons(AF_INET); bcopy(&myipaddr, response.addr, sizeof(struct in_addr)); length = sizeof(PROBE); bp = (char*)&response; display(bp, length); while(length) { if ((rv = api_send(newsock, bp, length, 0, "eprcd", TRUE)) < 0) return; length -= rv; bp -= rv; } api_release(newsock); api_close(newsock); } static void udp_thread(ccount, rpnum, mainsock) int ccount, rpnum, mainsock; { int newsock; struct sockaddr_in sin; PROBE *local_probe = (PROBE*)cbuff; char *app_nam = "erpcd:spawn_child"; #ifdef _WIN32 (void)api_close(mainsock); #else int pid; #ifdef SPT_TYPE setproctitle("%s", "udp"); #endif /* * instance of erpcd just forked * setup socket for communicating with client and exec() * to service requested */ #ifdef SYS_V (void)signal(SIGCLD, SIG_DFL); (void)signal(SIGHUP, SIG_DFL); #endif /* close master socket */ (void)api_close(mainsock); display(local_probe, sizeof(PROBE)); #endif /* _WIN32 */ sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = 0; if (debug > 1) fprintf(stdout, "erpcd: connecting to %s port %d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port)); if ((newsock = api_open(IPPROTO_UDP, &sin, app_nam, TRUE)) < 0) ErpcdExit(1); switch (api_bind(newsock, NULL, &sin, app_nam, TRUE)) { case 1: ErpcdExit(-1); case 2: ErpcdExit(1); case 0: default: break; } #ifdef EXOS from.sin_family = AF_INET; /* EXOS bug */ #endif switch (api_connect(newsock,&from,IPPROTO_UDP,app_nam,TRUE)) { case 0: break; case 1: ErpcdExit(1); case 2: ErpcdExit(-1); default: break; } if (local_probe->head.client == PET_AFIND) { declare_self(newsock); ErpcdExit(0); } else { switch (rpnum) { case COURRPN_BFS: bfs(newsock,(char *)cbuff, ccount); break; case COURRPN_ACP: #ifdef DEBUG_TO_FILE pid = sizeof(sin); getsockname(newsock,&sin,&pid); fprintf(dbgout, "%d: Spawned ACP child, sock %d, lport %d, fport %d.\n", getpid(),newsock,ntohs(sin.sin_port), ntohs(from.sin_port)); #endif acp(newsock,(char *)cbuff,ccount,from.sin_addr.s_addr); #ifdef DEBUG_TO_FILE fprintf(dbgout,"%d: ACP returned?\n",getpid()); #endif break; default: fprintf(stdout, "erpcd: Unknown remote program %d\n", rpnum); ErpcdExit(-1); } ErpcdExit(0); } } spawn_child(useudp) int useudp; { #ifdef _WIN32 #define MAX_PATH 260 int i; char szTemp[MAX_PATH]; PROCESS_INFORMATION exec_Info; STARTUPINFO StartInfo; sprintf(szTemp, "%s\\erpcd.exe", ErpcdOpt->htc.szAppPath); StartInfo.cb = sizeof (STARTUPINFO); StartInfo.lpReserved = NULL; StartInfo.lpDesktop = NULL; StartInfo.lpTitle = NULL; StartInfo.dwXCountChars = 80; StartInfo.dwYCountChars = 1180; StartInfo.dwFlags = STARTF_USECOUNTCHARS | STARTF_USESTDHANDLES; StartInfo.cbReserved2 = 0; StartInfo.lpReserved2 = NULL; StartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); StartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); StartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); { LONG dw; char newcommand[256]; sprintf(newcommand, "%s -#%d -%d", command_line, pcount+1, (useudp)?2:1); if ( !ResetEvent(useudp ? hEventOKToExitUDP : hEventOKToExitTCP) ) /* don't exit until child is ready.*/ { syslog(LOG_WARNING, "ResetEvent failed, %s, %d", (useudp ? "OKToExitUDP" : "OKToExitTCP"), GetLastError()); } for (i=0; i<20; i++) if (!CreateProcess(szTemp,newcommand,NULL,NULL,TRUE, NORMAL_PRIORITY_CLASS,NULL,NULL,&StartInfo, &exec_Info)) /* NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,NULL,NULL,&StartInfo, &exec_Info)) */ { DWORD dwErr = GetLastError(); syslog(LOG_ERR, "%d=Error 0x%lx: %d, not able to create process %d, szTemp=%s, command=%s\n" ,i, dwErr, dwErr, pcount+1, szTemp, newcommand); Sleep(3000 + i*1000); } else return 0; if ( !ReleaseSemaphore(hSemaphoreChildCount, 1, &dw) ) syslog(LOG_ERR, "ReleaseSemaphore failed for hSemaphoreChildCount %s", strerror( errno )); return -1; } #else int pid; pid = fork(); if (pid < 0) { perror("fork"); return pid; } if (pid > 0) { clientrec[child_count].pid = pid; if (debug) fprintf(stdout, "erpcd: forked, new pid=%d\n", pid); child_count++; return pid; } #endif random_seed(""); return(0); } static void spawn_child_udp(ccount, rpnum, mainsock) int ccount, rpnum, mainsock; { #ifdef _WIN32 spawn_child(1); #else clientrec[child_count].host = from.sin_addr; clientrec[child_count].port = ntohs(from.sin_port); clientrec[child_count].tcpflag = 0; if (spawn_child(1) == 0) #endif udp_thread(ccount, rpnum, mainsock); } static void tcp_thread(mainsock, newsock) int mainsock, newsock; { #ifndef _WIN32 int pid; #endif char *app_nam = "erpcd:spawn_child_tcp"; #ifdef SPT_TYPE setproctitle("%s", "tcp"); #endif /* * instance of erpcd just forked * setup socket for communicating with client and exec() * to service requested */ #ifdef SYS_V (void)signal(SIGCLD, SIG_DFL); (void)signal(SIGHUP, SIG_DFL); #endif /* close master socket */ (void)api_close(mainsock); acp_tcp(newsock, from.sin_addr.s_addr); ErpcdExit(0); } static void spawn_child_tcp(mainsock, newsock) int mainsock, newsock; { char *app_nam = "erpcd:spawn_child_tcp"; #ifdef _WIN32 spawn_child(0); /* in NT parent do the work other than child in UNIX */ #else clientrec[child_count].host = from.sin_addr; clientrec[child_count].port = ntohs(from.sin_port); clientrec[child_count].tcpflag = 1; if (spawn_child(0) == 0) #endif tcp_thread(mainsock, newsock); } #ifdef DEBUG_TO_FILE static void show_exit() { fprintf(dbgout,"%d: Exiting.\n",getpid()); } #endif static int start_socket(pd, addr) int pd; struct sockaddr_in *addr; { int socket; char *app_nam = "erpcd:start_socket"; addr->sin_family = AF_INET; addr->sin_addr.s_addr = INADDR_ANY; #ifdef _WIN32 if (debug) fprintf(stdout,"%d---Inherit = %d\n", pcount, Inherit); if (Inherit) { socket = (int)((pd == IPPROTO_TCP) ? ErpcdOpt->hMainTCPSocket : ErpcdOpt->hMainUDPSocket); SetEvent(pd == IPPROTO_TCP ? hEventOKToExitTCP : hEventOKToExitUDP); /* the parent is ok to exit. */ } else { #endif /* _WIN32 */ if ((socket = api_open(pd, addr, app_nam, TRUE)) < 0) ErpcdExit(1); if ((api_options & API_TO_DEBUG) == API_TO_DEBUG) if (api_opt(socket, API_TO_DEBUG, TRUE, app_nam) < 0) ErpcdExit(-1); if (pd == IPPROTO_TCP) { api_opt(socket, API_TO_REUSE, TRUE, app_nam); api_opt(socket, API_TO_OOB, TRUE, app_nam); api_opt(socket, API_TO_LINGER, TRUE, app_nam); } switch (api_bind(socket, NULL, addr, app_nam, TRUE)) { case 1: ErpcdExit(-1); break; case 2: ErpcdExit(1); break; case 0: default: break; } if (pd == IPPROTO_TCP) api_listen(socket, LISTEN_BACKLOG, app_nam, TRUE); #ifdef _WIN32 if (pd == IPPROTO_TCP) ErpcdOpt->hMainTCPSocket = (HANDLE) socket; else ErpcdOpt->hMainUDPSocket = (HANDLE) socket; } #endif /* _WIN32 */ return(socket); } static void udp_accept(socket) int socket; { #ifdef _WIN32 DWORD result; #endif /* * main loop * listens for ERPC service requests on reserved UDP port * forks appropriate server when properly identified request received */ for (;;) { UINT32 rpnum, pid; int rpver; int received; u_short verlo, verhi; int len, cc; char *app_nam = "erpcd:udp_accept"; struct eservent *esp; register struct chdr *ch = (struct chdr *)cbuff; int bad_format; /* * Wait for a remote procedure call message from anyone */ len = sizeof(from); /* Receive datagram from given source */ cc = sizeof(cbuff); if (debug) printf("UDP ready and waiting...\n"); #ifdef SPT_TYPE setproctitle("%s", "udp: listening"); #endif received = api_rcvud(&cc, &len, socket, NULL, (char *)cbuff, app_nam, TRUE, &from); #ifdef _WIN32 if ( WAIT_FAILED == WaitForSingleObject(hEventContinue, INFINITE) ) syslog(LOG_ERR, "WaitForSingleObject failed, %d, %s, %d", GetLastError(), __FILE__, __LINE__); #endif switch(received) { case 1: ErpcdExit(1); case 2: ErpcdExit(-1); case 3: continue; default: break; } if (debug) fprintf(stdout, "erpcd: received %d errno %d from %s[%d] port %d\n", cc, errno, inet_ntoa(from.sin_addr), len, ntohs(from.sin_port)); if (cc <= 0) continue; display(cbuff, cc); /* * check format */ bad_format = TRUE; switch(ntohs(ch->ch_client)) { case PET_ERPC: if (cc >= CHDRSIZE && ntohs(ch->ch_type) == C_CALL && ch->ch_tid == 0) bad_format = FALSE; break; case PET_AFIND: bad_format = FALSE; break; default: break; } if (bad_format) { if (debug) { fprintf(stdout, "erpcd: bad erpc header\n"); fprintf(stdout, "cc (%d) < (%d) CHDRSIZE\n", cc, CHDRSIZE); fprintf(stdout, "ch_client (%d) != (%d) PET_ERPC\n", ntohs(ch->ch_client), PET_ERPC); fprintf(stdout, "ch_type (%d) != (%d) C_CALL\n", ntohs(ch->ch_type), C_CALL); fprintf(stdout, "ch_tid (%d) != 0\n", ch->ch_tid); } continue; } pid = get_long(ch->ch_id); if (ntohs(ch->ch_client) == PET_AFIND) { PROBEHEAD *local_probehead = (PROBEHEAD*)cbuff; struct in_addr hostaddr, highaddr; char *addrlist; u_short host; int include, exclude; host = (DC_AUTHHOST | DC_BOOTHOST | DC_LOGHOST); if ( !(ntohs(local_probehead->devclass) & host) || !(ntohs((u_short)local_probehead->pcode) & PC_HOST) ) continue; addrlist = (char*)(local_probehead + 1); include = exclude = FALSE; while(!include && !exclude && *addrlist) { switch(addrlist[0]) { case ADDR_EXCL: addrlist++; bcopy(addrlist, (char*)&hostaddr, sizeof(struct in_addr)); addrlist += sizeof(struct in_addr); if (hostaddr.s_addr == myipaddr.s_addr) { exclude = TRUE; continue; } break; case ADDR_INCL: addrlist++; bcopy(addrlist, (char*)&hostaddr, sizeof(struct in_addr)); addrlist += sizeof(struct in_addr); if (hostaddr.s_addr == myipaddr.s_addr) { include = TRUE; continue; } break; case ADDR_RANGE_EXCL: addrlist++; bcopy(addrlist, (char*)&hostaddr, sizeof(struct in_addr)); addrlist += sizeof(struct in_addr); bcopy(addrlist, (char*)&highaddr, sizeof(struct in_addr)); addrlist += sizeof(struct in_addr); if (hostaddr.s_addr > myipaddr.s_addr || highaddr.s_addr < myipaddr.s_addr) { exclude = TRUE; continue; } break; case ADDR_RANGE_INCL: addrlist++; bcopy(addrlist, (char*)&hostaddr, sizeof(struct in_addr)); addrlist += sizeof(struct in_addr); bcopy(addrlist, (char*)&highaddr, sizeof(struct in_addr)); addrlist += sizeof(struct in_addr); if (hostaddr.s_addr <= myipaddr.s_addr && highaddr.s_addr >= myipaddr.s_addr) { include = TRUE; continue; } break; case ADDR_END: default: *addrlist = 0; break; } } if (!include) continue; } else { /* * Find requested remote program. */ seteservent(1); rpnum = get_long(ch->ch_rpnum); if ((esp = geteservbynum(rpnum)) == NULL) { /* * Would like to send a reject if request was not * broadcasted but there is no way to find this * out from here. */ erpc_reject(socket, &from, pid, CMJ_NOPROG, 0, 0); if (debug) { fprintf(stdout, "erpcd: Message rejected: prog %ld is not in %s file\n", rpnum, eservices_name); } continue; } rpver = ntohs(ch->ch_rpver); verlo = esp->es_verlo; verhi = esp->es_verhi; while ( (u_short)rpnum != esp->es_rpnum || (u_short)rpver < esp->es_verlo || (u_short)rpver > esp->es_verhi ) if ((esp = geteservent()) == NULL) break; endeservent(); if (esp == NULL) { /* * Would like to send reject if request not * broadcast but no way to find this out from here. */ erpc_reject(socket, &from, pid, CMJ_NOVERS, verlo, verhi); if (debug) { fprintf(stdout, "Message rejected: prog %ld ver %d excluded by %s\n", rpnum, rpver, eservices_name); } continue; } } /* * Reject the request if current child count is not * less than the maximum allowed count */ #ifdef _WIN32 if ( (result=WaitForSingleObject(hSemaphoreChildCount, 0)) == WAIT_TIMEOUT) #else if (child_count >= child_max) #endif { child_rejects++; /* * Would like to send reject if request not broadcast * but no way to find this out from here. */ erpc_reject(socket, &from, pid, CMJ_UNSPEC, verlo, verhi); if (debug) { fprintf(stdout, "Message rejected: exceeded session limit(%d)\n", child_max); } continue; } #ifdef _WIN32 else { if ( result == WAIT_FAILED ) { syslog(LOG_ERR, "WaitForSingleObject failed, %d, %s, %d", GetLastError(), __FILE__, __LINE__); } } #endif /* * Start requested remote program */ spawn_child_udp(cc, (ntohs(ch->ch_client) == PET_AFIND) ? 0 : esp->es_rpnum, socket); #ifdef _WIN32 break; #endif } } int newtcpsock; static void tcp_accept(socket) int socket; { char *app_nam = "erpcd:tcp_accept"; u_char *netaddr = (u_char*)&from.sin_addr.s_addr; int count = 0; while(1) { #ifndef TLI struct linger ling; #endif #ifdef SPT_TYPE setproctitle("%s", "tcp: listening"); #endif /* BLOCKS waiting for a connection request */ if (debug) printf("TCP ready and waiting...\n"); if ((newtcpsock = api_accept(socket, &from, app_nam, TRUE)) < 0) { ACP_USTRING buf; count++; if (count == 1) { sprintf(buf, "ACP Error in accept, errno is %d", errno); syslog(LOG_ERR, buf); } else if (count == 100) { sprintf(buf, "Fatal ACP Error in accept, errno is %d, erpcd is exiting", errno); syslog(LOG_CRIT, buf); api_release(socket, 2, app_nam); api_close(socket); #ifndef _WIN32 koolaidfest(0); /* die a horrible death, exit()s */ #else /* Should this shut down the erpc service in NT ? */ ErpcdExit(0); #endif /* _WIN32 */ } continue; } count = 0; #ifndef TLI api_opt(tcpsock, API_TO_REUSE, TRUE, app_nam); api_opt(tcpsock, API_TO_OOB, TRUE, app_nam); ling.l_onoff = 1; ling.l_linger = DEF_LINGER_TIME; setsockopt(tcpsock, SOL_SOCKET, SO_LINGER, (char*)&ling, sizeof(ling)); #endif if (debug) { printf("Accepted connection from %s\n", inet_ntoa(from.sin_addr)); } #ifdef _WIN32 { /* make new sock non-inheriable */ HANDLE hps = GetCurrentProcess(); HANDLE noinhsock; if ( !DuplicateHandle(hps, (HANDLE)newtcpsock, hps, &noinhsock, 0, FALSE, DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS) ) syslog(LOG_ERR, "DuplicateHandle failed, %d, %s, %d", GetLastError(), __FILE__, __LINE__); /* syslog(LOG_INFO, "Process %d, socket handles old(inheritable):%d, new(uninheritable):%d", _getpid(), newtcpsock, noinhsock);*/ CloseHandle((HANDLE)newtcpsock); newtcpsock = (int) noinhsock; } #endif spawn_child_tcp(socket, newtcpsock); api_close(newtcpsock); #ifdef _WIN32 break; #endif } } /* * ERPC listener */ int main(argc, argv, envp) int argc; char **argv; char **envp; { static char *app_nam="erpcd"; int error; struct hostent *host; char hoststring[64]; #ifndef _WIN32 time_t clock; int rc; #endif #ifdef LINUX struct sigaction sigaction_struct; #endif #ifdef _WIN32 { HANDLE handle; DWORD lerr; WSADATA WSAData; /* put any stderr output into stdout */ if(0 == _close(_fileno(stderr))) _dup (_fileno (stdout)); if ((error = WSAStartup(MAKEWORD(1,1), &WSAData)) != 0) { syslog(LOG_ERR, "WSAStartup Failed: %d\n", GetLastError()); } if ( !InitAlarmThread() ) /* initialize a thread to handle alarm */ { syslog(LOG_ERR, "Fatal Error, InitAlarmThread failed"); } handle = CreateSemaphore(NULL, ERPC_CHILD_MAX, ERPC_CHILD_MAX, "ChildCountSemaphore"); if ( handle == NULL ) { syslog(LOG_ERR, "Fatal Error, CreateSemaphore ChildCountSemaphore failed: %d", GetLastError()); } /* Initialize the critical section. */ InitializeCriticalSection(&GlobalCriticalSection); /* create all the synch object if they are not exist */ lerr = GetLastError(); Inherit = (lerr == ERROR_ALREADY_EXISTS); if (debug) fprintf(stdout,"%d--===============LastErr = %lx\n", pcount, lerr); if ( !GetPrimaryDomainName(sizeof(szDefaultDomain)) ) { syslog(LOG_ERR, "Can not get Primary Domain Name, Erpcd exiting"); exit(1); } if (Inherit) { hSemaphoreChildCount = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "ChildCountSemaphore"); if ( hSemaphoreChildCount == NULL ) { syslog(LOG_ERR, "OpenSemaphore failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventOKToExitUDP = OpenEvent(EVENT_ALL_ACCESS, FALSE,"OKToExitUDP"); if ( hEventOKToExitUDP == NULL ) { syslog(LOG_ERR, "OpenEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventOKToExitTCP = OpenEvent(EVENT_ALL_ACCESS, FALSE,"OKToExitTCP"); if ( hEventOKToExitTCP == NULL ) { syslog(LOG_ERR, "OpenEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventSIGHUP = OpenEvent(EVENT_ALL_ACCESS, FALSE,"SIGHUP"); if ( hEventSIGHUP == NULL ) { syslog(LOG_ERR, "OpenEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventSIGPWR = OpenEvent(EVENT_ALL_ACCESS, FALSE,"SIGPWR"); if ( hEventSIGPWR == NULL ) { syslog(LOG_ERR, "OpenEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventContinue = OpenEvent(EVENT_ALL_ACCESS, FALSE,"ServiceControlContinue"); if ( hEventContinue == NULL ) { syslog(LOG_ERR, "OpenEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventStop = OpenEvent(EVENT_ALL_ACCESS, FALSE,"ErpcdServiceControlStop"); if ( hEventSIGHUP == NULL ) { syslog(LOG_ERR, "OpenEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } /* Open the memory mapped file of Erpcd options */ hMapStructErpcdOption = OpenFileMapping (FILE_MAP_WRITE, FALSE, "StructErpcdOption"); if ( hMapStructErpcdOption == NULL ) { syslog(LOG_CRIT, "Fatal ACP Error, can't open StructErpcdOption filemap. Error: %s", strerror( errno )); exit(1); } ErpcdOpt = (StructErpcdOption *) MapViewOfFile (hMapStructErpcdOption, FILE_MAP_WRITE, 0, 0, 0); if ( ErpcdOpt == NULL ) { syslog(LOG_CRIT, "Fatal ACP Error, can't MapViewOfFile StructErpcdOption filemap. Error: %s", strerror( errno )); exit(1); } install_dir = ErpcdOpt->htc.szDirSecurity; root_dir = ErpcdOpt->htc.szDirLoadDump; /* Open the memory mapped file of RADIUS options */ hMapStructRadiusOption = OpenFileMapping (FILE_MAP_WRITE, FALSE, "StructRadiusOption"); if ( hMapStructRadiusOption == NULL ) { syslog(LOG_CRIT, "Fatal ACP Error, can't open StructRadiusOption filemap. Error: %s", strerror( errno )); exit(1); } RadiusOpt = (StructRadiusOption *) MapViewOfFile (hMapStructRadiusOption, FILE_MAP_WRITE, 0, 0, 0); if ( RadiusOpt == NULL ) { syslog(LOG_CRIT, "Fatal ACP Error, can't MapViewOfFile StructRadiusOption filemap. Error: %s", strerror( errno )); exit(1); } /* Copy the Radius server information */ if ( strcmp(ErpcdOpt->htc.szRadiusAuthenticationServer, "") == 0 ) strcpy(RadiusOpt->RadiusAuthenticationServer, ""); else strcpy(RadiusOpt->RadiusAuthenticationServer, ErpcdOpt->htc.szRadiusAuthenticationServer); if ( strcmp(ErpcdOpt->htc.szRadiusAccountingServer, "") == 0 ) strcpy(RadiusOpt->RadiusAccountingServer, ""); else if ( strcmp(ErpcdOpt->htc.szRadiusAccountingServer, "") == 0 ) strcpy(RadiusOpt->RadiusAccountingServer, RadiusOpt->RadiusAuthenticationServer); else strcpy(RadiusOpt->RadiusAccountingServer, ErpcdOpt->htc.szRadiusAccountingServer); memcpy(RadiusOpt->aServer, ErpcdOpt->htc.aServer, sizeof(ErpcdOpt->htc.aServer)); radius_server_count = ErpcdOpt->htc.SrvrCnt; } else { hSemaphoreChildCount = handle; hEventSIGHUP = CreateEvent(NULL, FALSE, FALSE, "SIGHUP"); if ( hEventSIGHUP == NULL ) { syslog(LOG_ERR, "CreateEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventSIGPWR = CreateEvent(NULL, TRUE, FALSE, "SIGPWR"); if ( hEventSIGPWR == NULL ) { syslog(LOG_ERR, "CreateEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventContinue = CreateEvent(NULL, TRUE, TRUE,"ServiceControlContinue"); if ( hEventContinue == NULL ) { syslog(LOG_ERR, "CreateEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventStop = CreateEvent(NULL, TRUE, FALSE,"ErpcdServiceControlStop"); if ( hEventStop == NULL ) { syslog(LOG_ERR, "CreateEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventOKToExitUDP = CreateEvent(NULL, TRUE, TRUE,"OKToExitUDP"); if ( hEventOKToExitUDP == NULL ) { syslog(LOG_ERR, "CreateEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hEventOKToExitTCP = CreateEvent(NULL, TRUE, TRUE,"OKToExitTCP"); if ( hEventOKToExitTCP == NULL ) { syslog(LOG_ERR, "CreateEvent failed, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } /* Create a memory mapped file for the Erpcd options */ hMapStructErpcdOption = CreateFileMapping ((HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, 0, sizeof(StructErpcdOption), "StructErpcdOption"); if ( hMapStructErpcdOption == NULL ) { syslog(LOG_CRIT, "Fatal ACP Error, can't create StructErpcdOption filemap. Error: %s", strerror( errno )); exit(1); } ErpcdOpt = (StructErpcdOption *) MapViewOfFile (hMapStructErpcdOption, FILE_MAP_WRITE, 0, 0, 0); if ( ErpcdOpt == NULL ) { syslog(LOG_CRIT, "Fatal ACP Error, can't MapViewOfFile StructErpcdOption filemap. Error: %s", strerror( errno )); exit(1); } /* Create a memory mapped file for the Radius options */ hMapStructRadiusOption = CreateFileMapping ((HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, 0, sizeof(StructRadiusOption), "StructRadiusOption"); if ( hMapStructRadiusOption == NULL ) { syslog(LOG_CRIT, "Fatal ACP Error, can't create StructRadiusOption filemap. Error: %s", strerror( errno )); exit(1); } RadiusOpt = (StructRadiusOption *) MapViewOfFile (hMapStructRadiusOption, FILE_MAP_WRITE, 0, 0, 0); if ( RadiusOpt == NULL ) { syslog(LOG_CRIT, "Fatal ACP Error, can't MapViewOfFile StructErpcdOption filemap. Error: %s", strerror( errno )); exit(1); } /* Read the Erpcd and RADIUS options into the memory mapped files */ ReadRegistryParam(); } if (WaitForSingleObject(hSemaphoreChildCount, 0) != WAIT_TIMEOUT) { LONG dw; ReleaseSemaphore(hSemaphoreChildCount, 1, &dw); if (debug) printf("Semaphore111 == %d\n", dw); } } #else /* not _WIN32 */ ErpcdOpt = &StructErpcdOptionBlock; myname = argv[0]; #endif /* _WIN32 */ erpcd_boottime = time((time_t *) 0); bzero(&myipaddr, sizeof(struct in_addr)); if (gethostname(hoststring, 64) == 0) if ((host = gethostbyname(hoststring)) != NULL) myipaddr.s_addr = *( (UINT32*)host->h_addr_list[0] ); /* process arguments */ handle_arguments(argc,argv); tzset(); #ifndef _WIN32 #ifndef NATIVEPASSWD ACP_PASSWD(passwd_name); ACP_PTMP(ptmp_name); ACP_LOCKFILE(lock_name); #else ACP_NATIVEPASSWD(passwd_name); ACP_NATIVEPTMP(ptmp_name); ACP_NATIVELOCKFILE(lock_name); #endif /* !NATIVEPASSWD */ #ifndef NATIVESHADOW ACP_SHADOW(shadow_name); ACP_STMP(stmp_name); #else ACP_NATIVESHADOW(shadow_name); ACP_NATIVESTMP(stmp_name); #endif /* !NATIVESHADOW */ ACP_REGIME(regime_file); ACP_GROUP(group_file); ACP_CONFIG(config_file); #endif /* !_WIN32 */ ACP_USERINFO(userinfo_name); ACP_ESERVICES(eservices_name); #ifdef DEBUG_TO_FILE unlink("erpcd.dbg"); if ((dbgout = fopen("erpcd.dbg","w")) == NULL) dbgout = stdout; else setlinebuf(dbgout); fprintf(dbgout,"%d: Running erpcd!\n",getpid()); on_exit(show_exit,NULL); #endif #ifdef notdef if (getuid()) { fprintf(stdout, "erpcd: not super user\n"); ErpcdExit(1); } #endif if (debug) { fprintf(stdout,"erpcd: using udp port %d.\n", (int)ntohs(udpaddr.sin_port)); fprintf(stdout,"erpcd: using tcp port %d.\n", (int)ntohs(tcpaddr.sin_port)); fprintf(stdout,"\tFile service directory: %s\n", root_dir); fprintf(stdout,"\tSecurity file directory: %s\n", install_dir); } #ifdef _WIN32 /* * If RADIUS is the selected security regime, * parse the radius parameters read from the registry/memory file * into a linked list structure and save the head. */ if ( ErpcdOpt->RadiusAuthentication == TRUE ) { radius_head = create_radius_configs(); } #else /* not WIN32 */ /* * Read the erpcd.conf file to save the serverinfo in a linked list * structure and store the head on return */ radius_head = create_radius_configs(); /* * Read erpcd.conf file to save trap host information * WHAT DO I DO WITH ERRORS??? */ (void)erpcd_read_config(); #endif #ifdef SPT_TYPE /* Initialize the routine to set the process title */ initsetproctitle(argc, argv, envp); #endif /* * this "mother" UDP socket receives generic ERPC requests * instances of a service are handled by a forked instance of the * server and use a new socket (eg, not this socket) */ if (use_udp) { udpsock = start_socket(IPPROTO_UDP, &udpaddr); if (udpsock < 0) use_udp = 0; /* slu - no udp socket */ } if (use_tcp) { tcpsock = start_socket(IPPROTO_TCP, &tcpaddr); if (tcpsock < 0) use_tcp = 0; /* slu - no tcp socket */ } if (!use_udp && !use_tcp) ErpcdExit(-1); #ifndef _WIN32 /* initialize the shared memory db */ rc = ses_open_db(raddb_numannex, ntohs(tcpaddr.sin_port)); /* initial num records */ if (rc == 0) { raddb_up = TRUE; } else { fprintf(stdout, "erpcd: RADIUS shared mem init failure %i\n",rc); syslog(LOG_CRIT, "RADIUS shared memory init failure"); } #endif #ifdef _WIN32 if (Inherit) /* first instance */ udp_child = use_udp; else { if (use_tcp && use_udp) { if (spawn_child(0)) ErpcdExit(1); /* spawn tcp child failed */ udp_child = TRUE; } else if (use_udp) /* use only udp */ udp_child = TRUE; } #else /* not _WIN32 */ if (!debug) { int f; #ifdef SPT_TYPE setproctitle("%s", "parent"); #endif if ((f=fork()) > 0) { if (showpid) printf("%d\n",f); ErpcdExit(0); } if (f < 0) { perror("fork"); ErpcdExit(1); } (void)close(0); (void)close(1); (void)close(2); #if defined(SYS_V) || defined(LINUX) f = open ("/dev/console", O_RDWR); if (f < 0) f = open ("/dev/tty", O_RDWR); if (f < 0) f = open ("/dev/null", O_RDWR); (void) dup2(STDIN, STDOUT); (void) dup2(STDIN, STDERR); (void) setpgrp(); #else (void) open("/dev/null", 2); (void) dup2(STDIN, STDOUT); (void) dup2(STDIN, STDERR); f = open("/dev/tty", 2); if (f >= 0) { ioctl(f, TIOCNOTTY, 0); (void) close(f); } (void) setpgrp(0, getpid()); #endif if (use_tcp && use_udp) { if ((f = fork()) > 0) /* parent */ { if (showpid) printf("%d\n",f); } else if (f < 0) /* fork failed */ { perror("fork"); ErpcdExit(1); } else /* child */ udp_child = TRUE; } else if (use_udp) /* use only udp */ udp_child = TRUE; } else { /* debug */ if (use_tcp && use_udp) { int f; #ifdef SPT_TYPE setproctitle("%s", "debug"); #endif f = fork(); if (f == 0) /* child */ { #ifdef SPT_TYPE setproctitle("%s", "debug/child"); #endif udp_child = TRUE; } else if (f<0){ /* error */ perror("fork"); ErpcdExit(1); } } else if (use_udp) udp_child = TRUE; } #endif /* _WIN32 */ #ifdef USE_SYSLOG #ifndef _WIN32 openlog(USE_SYSLOG,LOG_PID|LOG_NDELAY|LOG_NOWAIT,LOG_AUTH); #endif /* _WIN32 */ #endif /* USE_SYSLOG */ #ifndef _WIN32 #ifdef LINUX sigaction_struct.sa_handler = reaper; sigaction(SIGCHLD, &sigaction_struct, NULL); #else (void)signal(SIGCHLD, reaper); #endif (void)signal(SIGHUP, hangup); (void)signal(SIGUSR1, re_acpuser); (void)signal(SIGTERM, koolaidfest); /* If we've got a power-fail signal, then exit when we hear it. */ #ifdef SIGPWR (void)signal(SIGPWR,leave_erpcd); #endif #else /* _WIN32 */ hThreadSIGHUP = (HANDLE)_beginthread (hangup, 0, (void *)NULL); if ( hThreadSIGHUP == (HANDLE)0xFFFFFFFF ) { syslog(LOG_ERR, "_beginthread failed, hangup, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hThreadSIGPWR = (HANDLE)_beginthread (leave_erpcd, 0, (void *)NULL); if ( hThreadSIGPWR == (HANDLE)0xFFFFFFFF ) { syslog(LOG_ERR, "_beginthread failed, leave_erpcd, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hThreadUpdate = (HANDLE)_beginthread (UpdateErpcdOpt, 0, (void *)NULL); if ( hThreadUpdate == (HANDLE)0xFFFFFFFF ) { syslog(LOG_ERR, "_beginthread failed, UpdateErpcdOpt, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } hThreadServiceStop = (HANDLE)_beginthread (ServiceControlStop, 0, (void *)NULL); if ( hThreadServiceStop == (HANDLE)0xFFFFFFFF ) { syslog(LOG_ERR, "_beginthread failed, ServiceControlStop, %s, Line: %d, Error: %s", __FILE__, __LINE__, strerror( errno )); exit(1); } #endif /* _WIN32 */ /* * read "eservices" and initialize remote programs */ erpcd_init(); /* * read "acp_userinfo" and initialize user profile database. */ acpuser(0); if (udp_child) udp_accept(udpsock); else tcp_accept(tcpsock); #ifdef _WIN32 return 0; #endif } struct eservent * geteservbynum(rpnum) UINT32 rpnum; { register struct eservent *p; seteservent(0); while (p = geteservent()) if (p->es_rpnum == rpnum) break; endeservent(); return (p); } FILE *eservf = NULL; char line[BUFSIZ+1]; struct eservent eserv; int stayopen = 0; void seteservent(f) int f; { if (eservf == NULL) eservf = fopen(eservices_name,"r"); else rewind(eservf); stayopen |= f; } /* seteservent() */ void endeservent() { if (eservf && !stayopen) { (void)fclose(eservf); eservf = NULL; } } /* endeservent() */ static char * any(cp, match) register char *cp; char *match; { register char *mp, c; for (; c = *cp; cp++) for (mp = match; *mp; mp++) if (*mp == c) return (cp); return ((char *)0); } struct eservent * geteservent() { register char *p, *cp; if (eservf == NULL && (eservf = fopen(eservices_name, "r" )) == NULL) return (NULL); again: if ((p = fgets(line, BUFSIZ, eservf)) == NULL) return (NULL); if (*p == '#') goto again; cp = any(p, "#\n"); if (cp == NULL) goto again; *cp = '\0'; cp = any(p, " \t"); if (cp == NULL) goto again; *cp++ = '\0'; eserv.es_rpnum = (u_short)atoi(p); while (*cp == ' ' || *cp == '\t') cp++; p = cp; cp = any(p, " \t"); if (cp == NULL) goto again; *cp++ = '\0'; eserv.es_verlo = atoi(p); while (*cp == ' ' || *cp == '\t') cp++; p = cp; cp = any(p, " \t"); if (cp == NULL) goto again; *cp++ = '\0'; eserv.es_verhi = atoi(p); while (*cp == ' ' || *cp == '\t') cp++; p = cp; cp = any(p, " \t"); if (cp) *cp = '\0'; eserv.es_name = p; return (&eserv); } #ifdef IUNIX void dummy_alarm(dummy) int dummy; { } #endif /* * Collect status of exitting children. */ #ifndef _WIN32 void reaper(arg) int arg; { int savederrno = errno; int i,j; int status; #ifdef SYS_V /* decrement child_count for each status successfully returned */ #ifdef IUNIX int awas; void (*swas)(); /* * Work-around for a horrible IUNIX 3.2 bug; WNOHANG doesn't mean squat * on this machine. We have to time ourselves out of here! */ swas = signal(SIGALRM,dummy_alarm); awas = alarm(2); #endif while ((j=waitpid(-1, &status, WNOHANG)) > 0) { for (i = 0; i < child_count; i++) if (clientrec[i].pid == j) break; for (j = i+1; j < child_count; j++) clientrec[j-1] = clientrec[j]; child_count--; } #ifdef IUNIX alarm(awas); signal(SIGALRM,swas); #endif signal(SIGCHLD,reaper); #else /* decrement child_count for each status successfully returned */ signal(SIGCHLD,reaper); while ((j=wait3(&status, WNOHANG, (struct rusage *)0)) > 0) { for (i = 0; i < child_count; i++) if (clientrec[i].pid == j) break; for (j = i+1; j < child_count; j++) clientrec[j-1] = clientrec[j]; child_count--; } #endif errno = savederrno; } #endif /* * Initialize remote programs on the hangup signal, SIGHUP, a la init */ #ifdef _WIN32 void hangup(void *arg) #else void hangup(arg) int arg; #endif { #ifdef _WIN32 for(;;) { if ( WAIT_FAILED == WaitForSingleObject(hEventSIGHUP, INFINITE) ) syslog(LOG_ERR, "WaitForSingleObject failed, %d, %s, %d", GetLastError(), __FILE__, __LINE__); erpcd_init(); } #else erpcd_init(); #ifdef SYS_V signal(SIGHUP, hangup); #endif #endif } /* * Initialize acp user profile database */ void acpuser (dummy) int dummy; { #ifndef _WIN32 int mask; #endif int ret; /* char buf[128]; */ /* Deny access while parsing, and if an error occurs. */ deny_all_users = TRUE; #if defined(SYS_V) && !defined(BSDSIG) (void) sighold(SIGUSR1); #elif !defined(_WIN32) mask = sigblock(sigmask(SIGUSR1)); #endif /* defined(SYS_V) && !defined(BSDSIG) */ ret = open_user_profile_file(userinfo_name); if (ret == ACPU_ESUCCESS) ret = initialize_user_profile_file(0); #if defined(SYS_V) && !defined(BSDSIG) (void) sigrelse(SIGUSR1); #elif !defined(_WIN32) sigsetmask(mask); #endif /* defined(SYS_V) && !defined(BSDSIG) */ #ifdef SYS_V signal(SIGUSR1, acpuser); #endif /* acp_userinfo parsed successfully - don't deny access anymore. */ if(ret == ACPU_ESUCCESS) deny_all_users = FALSE; return; } /* * Frees old acp user profile database and initializes a new one. * Called on USR1 signal. */ void re_acpuser(dummy) int dummy; { close_user_profile_file(); clear_user_profile_info(); acpuser(0); } #ifdef _WIN32 void leave_erpcd ( void *dummy) #else void leave_erpcd (arg) int arg; #endif { #ifdef _WIN32 WaitForSingleObject(hEventSIGHUP, INFINITE); if (hEventSIGHUP != NULL) CloseHandle(hEventSIGHUP); #endif #ifdef DEBUG_TO_FILE fprintf(dbgout,"%d: leave_erpcd called.\n",getpid()); #endif ErpcdExit(0); } #ifndef _WIN32 void koolaidfest(dummy) int dummy; { /* Tell all the other processes in my group to exit as well. * If I'm running in debug and I type ^C at my terminal, it will * send SIGINT to everyone and they'll all go away. If I send * SIGTERM to everyone (including the shell) the shell goes away * and the user is logged out. */ if(!debug) kill(0, SIGTERM); ErpcdExit(0); } #endif void erpcd_init() { /* initialize secure annex cache for ACP (security) */ secure_cache(); }