diff options
author | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
---|---|---|
committer | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
commit | b2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch) | |
tree | cf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/slapd/ntwdog | |
download | ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.gz ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.tar.xz ds-b2093e3016027d6b5cf06b3f91f30769bfc099e2.zip |
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/slapd/ntwdog')
-rw-r--r-- | ldap/servers/slapd/ntwdog/Makefile | 60 | ||||
-rw-r--r-- | ldap/servers/slapd/ntwdog/cron_conf.c | 654 | ||||
-rw-r--r-- | ldap/servers/slapd/ntwdog/cron_conf.h | 86 | ||||
-rw-r--r-- | ldap/servers/slapd/ntwdog/ntcron.c | 156 | ||||
-rw-r--r-- | ldap/servers/slapd/ntwdog/ntwatchdog.c | 1163 |
5 files changed, 2119 insertions, 0 deletions
diff --git a/ldap/servers/slapd/ntwdog/Makefile b/ldap/servers/slapd/ntwdog/Makefile new file mode 100644 index 00000000..f727232c --- /dev/null +++ b/ldap/servers/slapd/ntwdog/Makefile @@ -0,0 +1,60 @@ +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001-2003 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# +# +# GNU Makefile for LDAP Server NT Service watchdog +# + +LDAP_SRC = ../../.. +MCOM_ROOT = ../../../../.. + +NOSTDCLEAN=true # don't let nsconfig.mk define target clean +NOSTDSTRIP=true # don't let nsconfig.mk define target strip +NSPR20=true # probably should be defined somewhere else (not sure where) + +OBJDEST = $(OBJDIR)/ntwdog/obj +SLAPD_OBJDEST= $(OBJDIR)/obj +BINDIR = $(LDAP_SERVER_RELDIR) +LDAP_LIBDIR = $(OBJDIR)/lib + +include $(MCOM_ROOT)/ldapserver/nsconfig.mk +include $(LDAP_SRC)/nsldap.mk + +ifeq ($(ARCH), WINNT) +SUBSYSTEM=windows +endif + +#INCLUDES += -I$(MCOM_ROOT)/ldapserver/include/libadmin + +DS_SERVER_DEFS = -DNS_DS + +NTWDOG_OBJS= ntwatchdog.o + +OBJS = $(addprefix $(OBJDEST)/, $(NTWDOG_OBJS)) + +LIBS_DEP = $(LDAP_LIBUTIL_DEP) $(LIBADMIN_DEP) + +LIBS = $(LDAP_LIBUTIL) + +EXTRA_LIBS += $(LIBS) + +NTWDOG = $(addprefix $(BINDIR)/, ns-slapd.exe) + +all: $(OBJDEST) $(BINDIR) $(NTWDOG) + +$(OBJDEST): + $(MKDIR) $(OBJDEST) + +$(NTWDOG): $(OBJS) $(LIBS_DEP) + $(LINK_EXE) + +veryclean: clean + +clean: + $(RM) $(OBJS) + $(RM) $(NTWDOG) + diff --git a/ldap/servers/slapd/ntwdog/cron_conf.c b/ldap/servers/slapd/ntwdog/cron_conf.c new file mode 100644 index 00000000..8d60191a --- /dev/null +++ b/ldap/servers/slapd/ntwdog/cron_conf.c @@ -0,0 +1,654 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include <windows.h> +#include <stdio.h> +#include <string.h> +#include <process.h> +#include <stdlib.h> +#include <stdarg.h> +#include "cron_conf.h" + +#define NSAPI_PUBLIC + +#ifndef BUF_SIZE +#define BUF_SIZE 4096 +#endif + +#ifndef S_BUF_SIZE +#define S_BUF_SIZE 1024 +#endif + +#ifdef XP_WIN32 +#pragma warning (disable: 4005) // macro redifinition // +#define MALLOC(size) malloc(size) +#define REALLOC(x, size) realloc(x, size) +#define FREE(x) free((void*) x) +#define STRDUP(x) strdup(x) +#define strcasecmp(x, y) stricmp(x, y) +#pragma warning (default: 4005) // macro redifinition // +#endif + +static char *admroot; +static char *nsroot; + +#define DAILY "Sun Mon Tue Wed Thu Fri Sat" + +static cron_conf_list *cclist = NULL; +static cron_conf_list *cctail = NULL; +static char *conffile = NULL; + +#ifndef CRON_CONF_STAND_ALONE +static void set_roots() +{ + char *ar = ADMCONFDIR; + if(ar) + admroot = STRDUP(ar); +} +#endif + +/* General note: strtok() is not MT safe on Unix , but it is okay to call + here because this file is NT only and strtok() is MT safe on NT */ + +static char *nocr(char *buf) +{ + if (buf) + { + if(buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + } + + return buf; +} + +static int debug(char *fmt, ...) +{ + va_list args; + char buf[BUF_SIZE]; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + fprintf(stdout, "<<DEBUG>> %s <<DEBUG>>\n", buf); + fflush(stdout); + + return 1; +} + +static char *get_conf_file() +{ + static char conffile [S_BUF_SIZE]; + char nsconfile[S_BUF_SIZE]; + char buf [BUF_SIZE]; + char *r, *p; + FILE *fp; + int flag = 0; + + if (admroot) + sprintf(nsconfile, "%s/ns-cron.conf", admroot); + else + sprintf(nsconfile, "%s/admin-serv/config/ns-cron.conf", nsroot); + + if (!(fp = fopen(nsconfile, "r"))) + return NULL; + + while(fgets(buf, sizeof(buf), fp)) + { + r = strtok(buf, " \t\n"); + if (!r) /* bad line, ignore */ + continue; + + p = strtok(NULL, " \t\n"); + if (!p) /* bad line, ignore */ + continue; + + if (!strcasecmp(r, "ConfFile")) + { + /* if filename without path is specified, default to admin svr dir */ + if((strchr(p, '\\') == NULL) && + (strchr(p, '/') == NULL)) + sprintf(conffile, "%s/%s", admroot, p); + else + sprintf(conffile, "%s", p); + flag++; + break; + } + } + + fclose(fp); + + if (!flag) + return NULL; + + return conffile; +} + + +#ifndef CRON_CONF_STAND_ALONE +NSAPI_PUBLIC +#endif +cron_conf_obj *cron_conf_create_obj(char *name, char *command, char *dir, + char *user, char *start_time, char *days) +{ + cron_conf_obj *object; + char *d = NULL; + + object = (cron_conf_obj*)MALLOC(sizeof(cron_conf_obj)); + + object->name = (name) ? STRDUP(name) : NULL; + object->command = (command) ? STRDUP(command) : NULL; + object->dir = (dir) ? STRDUP(dir) : NULL; + object->user = (user) ? STRDUP(user) : NULL; + object->start_time = (start_time) ? STRDUP(start_time) : NULL; + +#if 1 + if (days) + { + if (!(strcasecmp(days, "Daily"))) + d = STRDUP(DAILY); + else + d = STRDUP(days); + } +#else + d = STRDUP("Wed Thu"); +#endif + + object->days = d; + + return object; +} + + +static void cron_conf_free_listobj(cron_conf_list *lobj) +{ + cron_conf_obj *obj = lobj->obj; + + + if (obj) + { + if(obj->name) FREE(obj->name); + if(obj->command) FREE(obj->command); + if(obj->dir) FREE(obj->dir); + if(obj->user) FREE(obj->user); + if(obj->start_time) FREE(obj->start_time); + if(obj->days) FREE(obj->days); + + FREE(obj); + } + + FREE(lobj); +} + + +static cron_conf_obj *get_object(FILE *fp) +{ + cron_conf_obj *object; + char name [S_BUF_SIZE]; + char command [S_BUF_SIZE]; + char dir [S_BUF_SIZE]; + char user [S_BUF_SIZE]; + char start_time[S_BUF_SIZE]; + char days [S_BUF_SIZE]; + char buf [BUF_SIZE]; + char *p, *q; + int flag = 0; + int hascom, hasdir, hasuser, hastime, hasdays; + + p = fgets(buf, sizeof(buf), fp); + + if (!p) + return NULL; + /* else debug("Read line '%s'", nocr(buf)); */ + + if (strncmp(buf, "<Object", 7)) + return NULL; + + hascom = hasdir = hasuser = hastime = hasdays = 0; + + p = strtok(buf, "<=>\n\t "); + if (!p) + return NULL; + + p = strtok(NULL, "<=>\n\t "); + if (!p) + return NULL; + + p = strtok(NULL, "<=>\n\t "); + if (!p) + return NULL; + + sprintf(name, "%s", p); + /* debug("Setting name to '%s'", name); */ + + while(fgets(buf, sizeof(buf), fp)) + { + /* debug("Read line '%s'", nocr(buf)); */ + + p = strtok(buf, " \t\n"); + + if (!p) + continue; + + if (!strcasecmp(p, "</Object>")) + { + flag++; + break; + } + + if(!strcasecmp(p, "Command")) + { + q = strtok(NULL, "\n"); + + if (q) + q = strchr(q, '\"'); + + if (q) + q++; + + if (q) + { + if (!hascom) + { + /* get rid of quotes */ + p = strrchr(q, '\"'); + + if (p) + *p = '\0'; + + if (q) + { + sprintf(command, "%s", q); + /* debug("Setting command to '%s'", command); */ + hascom++; + } + } + else /* already has a command */ + ; /* ignore */ + } + continue; + } + + if(!strcasecmp(p, "Dir")) + { + q = strtok(NULL, "\n"); + + if (q) + q = strchr(q, '\"'); + + if (q) + q++; + + if (q) + { + if (!hasdir) + { + /* get rid of quotes */ + p = strrchr(q, '\"'); + + if (p) + *p = '\0'; + + if (q) + { + sprintf(dir, "%s", q); + /* debug("Setting dir to '%s'", dir); */ + hasdir++; + } + } + else /* already has a dir */ + ; /* ignore */ + } + continue; + } + + else if(!strcasecmp(p, "User")) + { + q = strtok(NULL, " \t\n"); + + if (q) + { + if (!hasuser) + { + sprintf(user, "%s", q); + /* debug("Setting user to '%s'", user); */ + hasuser++; + } + else /* already has a user */ + ; /* ignore */ + } + continue; + } + + else if(!strcasecmp(p, "Time")) + { + q = strtok(NULL, "\n"); + + if (q) + { + if (!hastime) + { + sprintf(start_time, "%s", q); + /* debug("Setting time to '%s'", start_time); */ + hastime++; + } + else /* already has a time */ + ; /* ignore */ + } + continue; + } + + else if(!strcasecmp(p, "Days")) + { + q = strtok(NULL, "\n"); + + if (q) + { + if (!hasdays) + { + sprintf(days, "%s", q); + /* debug("Setting days to '%s'", days); */ + hasdays++; + } + else /* already has days */ + ; /* ignore */ + } + continue; + } + + else + { + /* gibberish... ignore... will be fixed when + file is rewritten */ + continue; + } + } + + object = cron_conf_create_obj(name, + (hascom) ? command : NULL, + (hasdir) ? dir : NULL, + (hasuser) ? user : NULL, + (hastime) ? start_time : NULL, + (hasdays) ? days : NULL); + + return object; +} + + +static void cron_conf_write_stream(FILE *fp) +{ + cron_conf_obj *obj; + cron_conf_list *lobj; + + for(lobj = cclist; lobj; lobj = lobj->next) + { + obj = lobj->obj; + + fprintf(fp, "<Object name=%s>\n", (obj->name) ? obj->name : "?"); + fprintf(fp, " Command \"%s\"\n", (obj->command) ? obj->command : "?"); + if (obj->dir) + fprintf(fp, " Dir \"%s\"\n", obj->dir); + if (obj->user) + fprintf(fp, " User %s\n", obj->user); + fprintf(fp, " Time %s\n", (obj->start_time) ? obj->start_time : "?"); + fprintf(fp, " Days %s\n", (obj->days) ? obj->days : "?"); + fprintf(fp, "</Object>\n"); + } +} + + +static void cron_conf_delete(char *name, cron_conf_obj *cco) +{ + cron_conf_list *lobj = NULL; + cron_conf_list *pobj = NULL; + + if (!cclist) + return; + + if (!strcmp(cclist->name, name)) + { + lobj = cclist; + cclist = cclist->next; + if (cctail == lobj) + cctail = cclist; + + cron_conf_free_listobj(lobj); + } + else + { + pobj = cclist; + + for(lobj = cclist->next; lobj; lobj = lobj->next) + { + if(!strcmp(lobj->name, name)) + { + if (lobj == cctail) + cctail = pobj; + + pobj->next = lobj->next; + cron_conf_free_listobj(lobj); + + break; + } + + pobj = lobj; + } + } + + return; +} + +#ifndef CRON_CONF_STAND_ALONE +NSAPI_PUBLIC +#endif +int cron_conf_read() +{ + FILE *fp; + cron_conf_obj *obj; + cron_conf_list *lobj; + +#ifndef CRON_CONF_STAND_ALONE + set_roots(); +#endif + + if (!(conffile = get_conf_file())) + { + /* debug("Conffile is null"); */ + return 0; + } + /* else debug("Conffile: '%s'", conffile); */ + + if (!(fp = fopen(conffile, "r"))) + { + /* debug("Couldn't open conffile"); */ + return 0; + } + + while((obj = get_object(fp))) + { + lobj = (cron_conf_list*)MALLOC(sizeof(struct cron_conf_list)); + lobj->name = obj->name; + lobj->obj = obj; + lobj->next = NULL; + + /* debug("Created a list object named '%s'", lobj->name); */ + + if(cclist == NULL) /* first object */ + { + cclist = cctail = lobj; + } + else + { + cctail->next = lobj; + cctail = lobj; + } + + /* debug("List now, head: '%s', tail: '%s'", + cclist->name, cctail->name); */ + } + + fclose(fp); + + return 1; +} + +#ifndef CRON_CONF_STAND_ALONE +NSAPI_PUBLIC +#endif +cron_conf_obj *cron_conf_get(char *name) +{ + cron_conf_obj *obj = NULL; + cron_conf_list *lobj = NULL; + + /* find object */ + for(lobj = cclist; lobj; lobj = lobj->next) + { + if(!strcmp(lobj->name, name)) + { + obj = lobj->obj; + break; + } + } + +#if 0 + if (obj) + { + debug("Found object %s", obj->name); + debug("obj->command = %s", (obj->command) ? obj->command : "NULL"); + debug("obj->dir = %s", (obj->dir) ? obj->dir : "NULL"); + debug("obj->user = %s", (obj->user) ? obj->user : "NULL"); + debug("obj->start_time = %s", (obj->start_time) ? obj->start_time : "NULL"); + debug("obj->days = %s", (obj->days) ? obj->days : "NULL"); + } +#endif + + return obj; +} + + +#ifndef CRON_CONF_STAND_ALONE +NSAPI_PUBLIC +#endif +cron_conf_list *cron_conf_get_list() +{ + return cclist; +} + +#ifndef CRON_CONF_STAND_ALONE +NSAPI_PUBLIC +#endif +cron_conf_obj *cron_conf_set(char *name, cron_conf_obj *cco) +{ + cron_conf_obj *obj = NULL; + cron_conf_list *lobj = NULL; + + if (!name) + return NULL; + + if (!cco) + { + cron_conf_delete(name, cco); + return NULL; + } + else /* cco exists */ + { + /* find object */ + obj = cron_conf_get(name); + + + if (obj) /* found it */ + { + if (cco->command) + { + FREE(obj->command); + obj->command = cco->command; + } + + if (cco->dir) + { + FREE(obj->dir); + obj->dir = cco->dir; + } + + if (cco->user) + { + FREE(obj->user); + obj->user = cco->user; + } + + if (cco->start_time) + { + FREE(obj->start_time); + obj->start_time = cco->start_time; + } + + if (cco->days) + { + FREE(obj->days); + obj->days = cco->days; + } + + FREE(cco); + } + else /* couldn't find it */ + { + obj = cco; + + lobj = (cron_conf_list*)MALLOC(sizeof(cron_conf_list)); + lobj->name = obj->name; + lobj->obj = obj; + lobj->next = NULL; + + if(cclist == NULL) /* first object */ + { + cclist = cctail = lobj; + } + else + { + cctail->next = lobj; + cctail = lobj; + } + } + } + + return obj; +} + +void cron_conf_write() +{ + FILE *fp; + + if (!conffile) + conffile = get_conf_file(); + + if(!(fp = fopen(conffile, "w"))) + return; + + cron_conf_write_stream(fp); + + fclose(fp); +} + + +#ifndef CRON_CONF_STAND_ALONE +NSAPI_PUBLIC +#endif +void cron_conf_free() +{ + cron_conf_list *lobj = NULL; + + /* find object */ + while(cclist) + { + lobj = cclist; + cclist = cclist->next; + + cron_conf_free_listobj(lobj); + } + + cclist = cctail = NULL; +} + diff --git a/ldap/servers/slapd/ntwdog/cron_conf.h b/ldap/servers/slapd/ntwdog/cron_conf.h new file mode 100644 index 00000000..23a32463 --- /dev/null +++ b/ldap/servers/slapd/ntwdog/cron_conf.h @@ -0,0 +1,86 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +/*********************************************************************** +** $Id: cron_conf.h,v 1.1 2005/01/21 00:40:52 cvsadm Exp $ +** +** +** NAME +** cron_conf.h +** +** DESCRIPTION +** +** +** AUTHOR +** <robw@netscape.com> +** +***********************************************************************/ + +#ifndef _CRON_CONF_H_ +#define _CRON_CONF_H_ + +/*********************************************************************** +** Includes +***********************************************************************/ +/* read and write to cron.conf, cron_conf.c */ +/* Alex Feygin, 3/22/96 */ +typedef struct cron_conf_obj +{ + char *name; + char *command; + char *dir; + char *user; + char *start_time; + char *days; +} +cron_conf_obj; + +typedef struct cron_conf_list +{ + char *name; + cron_conf_obj *obj; + struct cron_conf_list *next; +} +cron_conf_list; + +/* Reads cron.conf to a null terminated list of cron_conf_objects; returns + 0 if unable to do a read; 1 otherwise */ +int cron_conf_read(); + +/* gets a cron object, NULL if it doesnt exist */ +cron_conf_obj *cron_conf_get(char *name); + +/* returns a NULL-terminated cron_conf_list of all the cron conf objects */ +cron_conf_list *cron_conf_get_list(); + +/* Creates a cron conf object; all these args get STRDUP'd in the function + so make sure to free up the space later if need be */ +cron_conf_obj *cron_conf_create_obj(char *name, char *command, + char *dir, char *user, + char *start_time, char *days); + +/* Puts a cron conf object into list or updates it if it already in there. + Returns either the object passed or the object in there already; + cco may be FREE'd during this operation so if you need the object + back, call it like so: + + cco = cron_conf_set(cco->name, cco); + + calling cron_conf_set with a NULL cco will cause the 'name' object + to be deleted. +*/ +cron_conf_obj *cron_conf_set(char *name, cron_conf_obj *cco); + +/* write out current list of cron_conf_objects to cron.conf file */ +void cron_conf_write(); + +/* free all cron conf data structures */ +void cron_conf_free(); + +#define MAGNUS_CONF "magnus.conf" +#define ADMCONFDIR "../config/" + + +#endif /* _CRON_CONF_H_ */ diff --git a/ldap/servers/slapd/ntwdog/ntcron.c b/ldap/servers/slapd/ntwdog/ntcron.c new file mode 100644 index 00000000..98b4cae3 --- /dev/null +++ b/ldap/servers/slapd/ntwdog/ntcron.c @@ -0,0 +1,156 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +// // +// Name: NTCRON // +// Platforms: WIN32 // +// Description: unix cron functionality in a separate thread // +// Notes: // +// The following assumptions are made: // +// - gszServerRoot is set to c:\netscape\server // +// - ns-cron.conf and cron.conf are available // +// Todo: // +// - handle time format variations of hh:mm // +// - keep track of children // +// ...................................................................... // +// Revision History: // +// 03-26-96 Initial Version, Andy Hakim (ahakim@netscape.com) // +// 07-10-96 Modified for Directory Server, pkennedy@netscape.com // +//--------------------------------------------------------------------------// +#include <windows.h> +#include "ntwatchdog.h" +#include "ntslapdmessages.h" // event log msgs constants // +#include "cron_conf.h" + +static cron_conf_list *cclist = NULL; + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL CRON_CheckDay(LPSYSTEMTIME lpstNow, char *szDays) +{ + BOOL bReturn = FALSE; + char szToday[16]; + if(GetDateFormat((LCID)NULL, 0, lpstNow, "ddd", szToday, sizeof(szToday)) != 0) + { + strlwr(szDays); + strlwr(szToday); + if(strstr(szDays, szToday) != NULL) + bReturn = TRUE; + } + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL CRON_CheckTime(LPSYSTEMTIME lpstNow, char *szTime) +{ + BOOL bReturn = FALSE; + char szCurrentTime[16]; + char szStartTime[16]; + + strcpy(szStartTime, szTime); + + if(szTime[1] == ':') + wsprintf(szStartTime, "0%s", szTime); + + if(GetTimeFormat((LCID)LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, lpstNow, "hh:mm", szCurrentTime, sizeof(szCurrentTime)) != 0) + { + if(strcmp(szCurrentTime, szStartTime) == 0) + bReturn = TRUE; + } + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL CRON_StartJob(PROCESS_INFORMATION *pi, cron_conf_obj *cco) +{ + BOOL bReturn = FALSE; + STARTUPINFO sui; + + sui.cb = sizeof(STARTUPINFO); + sui.lpReserved = 0; + sui.lpDesktop = NULL; + sui.lpTitle = NULL; + sui.dwX = 0; + sui.dwY = 0; + sui.dwXSize = 0; + sui.dwYSize = 0; + sui.dwXCountChars = 0; + sui.dwYCountChars = 0; + sui.dwFillAttribute = 0; + sui.dwFlags = STARTF_USESHOWWINDOW; + sui.wShowWindow = SW_SHOWMINIMIZED; + sui.cbReserved2 = 0; + sui.lpReserved2 = 0; + sui.hStdInput = 0; + sui.hStdOutput = 0; + sui.hStdError = 0; + + bReturn = CreateProcess(NULL, cco->command, NULL, NULL, + TRUE, 0, NULL, cco->dir, &sui, pi ); + if(!bReturn) + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_CRON_STARTFAILED, cco->name); + + return(bReturn); +} + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL CRON_CheckConfFile() +{ + BOOL bReturn = FALSE; + PROCESS_INFORMATION pi; + SYSTEMTIME stNow; + + GetLocalTime(&stNow); // note: this provides time adjusted for local time zone + + if(cron_conf_read()) + cclist = cron_conf_get_list(); + + while((cclist) && (cclist->obj)) + { + cron_conf_obj *cco = cclist->obj; + if((cco->days) && (cco->start_time) && (cco->command)) + { + if(CRON_CheckDay(&stNow, cco->days) && CRON_CheckTime(&stNow, cco->start_time)) + { + bReturn = CRON_StartJob(&pi, cco); + CLOSEHANDLE(pi.hProcess); + CLOSEHANDLE(pi.hThread); + } + } + cclist = cclist->next; + } + cron_conf_free(); + return bReturn; +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +LPTHREAD_START_ROUTINE CRON_ThreadProc(HANDLE hevWatchDogExit) +{ + BOOL bExit = FALSE; + while(!bExit) + { + CRON_CheckConfFile(); + if(WaitForSingleObject(hevWatchDogExit, 1000*DEFAULT_CRON_TIME) != WAIT_TIMEOUT) + bExit = TRUE; + } + return 0; +} diff --git a/ldap/servers/slapd/ntwdog/ntwatchdog.c b/ldap/servers/slapd/ntwdog/ntwatchdog.c new file mode 100644 index 00000000..ef8e795c --- /dev/null +++ b/ldap/servers/slapd/ntwdog/ntwatchdog.c @@ -0,0 +1,1163 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#pragma warning(disable : 4001) +// disable warning C4001: nonstandard extension 'single line comment' was used + +// // +// Name: NTWATCHDOG // +// Platforms: WIN32 // +// Description: shell for nt directory server, runs as service, launches // +// server, monitors it, re-launches if server crashes, // +// Notes: // +// ...................................................................... // +// Watchdog can be run as an application or a service. When run as a // +// service, it uses the service name from the SCM for the server name. // +// When run as an application, it uses the command line to determine // +// the server name. The command line can be one of two formats: // +// c:\navgold\server\slapd-kennedy\config // +// or // +// slapd-kennedy // +// ...................................................................... // +// server file "lib\base\servssl.c" was changed // +// - added code to get password from WatchDog process // +// ...................................................................... // +// server file "httpd\src\ntmain.c" was changed // +// - server always runs as an application // +// - changed hServerDoneEvent global name to "NS_service_name" // +// this was necessary so that WatchDog can trap the "service_name" event // +// - above changes were also made in MultipleInstances() // +// ...................................................................... // +// server file "lib\libmessages\messages.mc" was changed // +// - added a couple of extra messages for watchdog event logging // +// - watchdog is dependent on the server's eventlog source name // +// ...................................................................... // +// Revision History: // +// 01-12-96 Initial Version, Andy Hakim (ahakim@netscape.com) // +// 02-01-96 changed restart logic, now based on infant mortality time // +// instead of server exit code // +// 07-10-96 Modified for Directory Server, pkennedy@netscape.com // +// // +//--------------------------------------------------------------------------// +#include <windows.h> +#include <stdio.h> +#include <string.h> +#include <process.h> +#include "ntslapdmessages.h" // event log msgs constants // +#include "regparms.h" // product name, etc // +#include "ntwatchdog.h" +#include "version.h" +#include "ntresource.h" +#include "proto-ntutil.h" + +#ifdef PUMPKIN_HOUR +#include <time.h> +#endif + +//--------------------------------------------------------------------------// +// global variables // +//--------------------------------------------------------------------------// +SERVICE_STATUS_HANDLE gsshServiceStatus = 0L; +HWND ghWndMain = NULL; +HANDLE ghevWatchDogExit = NULL; +HINSTANCE ghInstance = NULL; +HANDLE ghdlgPassword = NULL; // handle to password dialog window +HANDLE ghDuplicateProcess = NULL; // process handle with PROCESS_VM_READ access +HANDLE ghServerProcess = NULL; // used by app window in TerminateProcess() +HANDLE ghServerThread0 = NULL; // used by app window in Suspend/ResumeThread() +HANDLE ghWdogProcess = NULL; +char gszServerConfig[MAX_LINE]; // ex: c:\netscape\server\slapd-kennedy\config +char gszServerName[MAX_LINE]; // ex: slapd-kennedy +char gszServerRoot[MAX_LINE]; // ex: c:\netscape\server +char gszPassword[2048]; +DWORD gdwServiceError = NO_ERROR; // return error code for service +DWORD gdwLastStatus = SERVICE_RUNNING; + +//--------------------------------------------------------------------------// +// This is the shutdown handler we register via SetConsoleCtrlHandler() +// It is really the only guaranteed means we have of shutting down gracefully +// when the sytem is shutting down. The Service Manager mechanism is not +// guaranteed to work. +//--------------------------------------------------------------------------// + +BOOL WINAPI WD_ControlHandler(DWORD dwCtrlType) +{ + if (dwCtrlType == CTRL_SHUTDOWN_EVENT) { + SetEvent(ghevWatchDogExit); + WaitForSingleObject(ghWdogProcess, 1000 * DEFAULT_KILL_TIME); + return TRUE; + } + return FALSE; +} + + +//--------------------------------------------------------------------------// +// calc szServerRoot given szServerName // +//--------------------------------------------------------------------------// +BOOL WD_GetServerConfig(char *szServerId, char *szServerRoot, LPDWORD cbServerRoot) +{ + BOOL bReturn = FALSE; + HANDLE hSlapdKey = 0; + char szSlapdKey[MAX_PATH]; + DWORD dwValueType; + DWORD dwResult = 0; + + // don't want to monitor Admin server + if(strcmp(ADM_KEY_ROOT, szServerId) == 0) + return(bReturn); + + // query registry key to figure out config directory + sprintf(szSlapdKey, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT, + szServerId); + + dwResult = RegOpenKey(HKEY_LOCAL_MACHINE, szSlapdKey, &hSlapdKey); + if(dwResult == ERROR_SUCCESS) + { + dwResult = RegQueryValueEx(hSlapdKey, VALUE_CONFIG_PATH, NULL, + &dwValueType, (LPBYTE)szServerRoot, cbServerRoot); + if(dwResult == ERROR_SUCCESS) + bReturn = TRUE; + RegCloseKey(hSlapdKey); + } + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// get server's id based on index value that corresponds to the order in // +// which it is listed under the the registry \SOFTWARE\Netscape\.. // +//--------------------------------------------------------------------------// +BOOL WD_GetServerId(IN DWORD dwSubKey, OUT char *szServerId, IN OUT LPDWORD cbServerId) +{ + BOOL bReturn = FALSE; + static HANDLE hSlapdKey = 0; + DWORD dwResult = ERROR_SUCCESS; + FILETIME ftLastWrite; + char szSlapdKey[MAX_LINE]; + + if(dwSubKey == 0) { + sprintf(szSlapdKey, "%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT); + dwResult = RegOpenKey(HKEY_LOCAL_MACHINE, szSlapdKey, + &hSlapdKey); + } + + if(dwResult == ERROR_SUCCESS) + { + dwResult = RegEnumKeyEx(hSlapdKey, dwSubKey, szServerId, + cbServerId, NULL, NULL, NULL, &ftLastWrite); + if(dwResult == ERROR_SUCCESS) + { + bReturn = TRUE; + } + else + { + RegCloseKey(hSlapdKey); + hSlapdKey = 0; + } + } + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL WD_IsServiceRunning(char *szServerId) +{ + BOOL bReturn = FALSE; + SC_HANDLE hscManager; + SC_HANDLE hscService; + SERVICE_STATUS ssServiceStatus; + + if(hscManager = OpenSCManager(NULL, NULL, GENERIC_READ)) + { + if(hscService = OpenService(hscManager, szServerId, SERVICE_QUERY_STATUS)) + { + if(QueryServiceStatus(hscService, &ssServiceStatus)) + { + if(ssServiceStatus.dwCurrentState != SERVICE_STOPPED) + { + bReturn = TRUE; + } + } + CloseServiceHandle(hscService); + } + CloseServiceHandle(hscManager); + } + return(bReturn); +} + + + + + +//--------------------------------------------------------------------------// +// get a list of installed servers // +//--------------------------------------------------------------------------// +int WD_GetRunningServerCount(void) +{ + int nServerCount = 0; + int nEnumIndex = 0; + char szServerId[MAX_PATH]; + DWORD cbServerId = sizeof(szServerId); + char szServerRoot[MAX_PATH]; + DWORD cbServerRoot = sizeof(szServerRoot); + + while(WD_GetServerId(nEnumIndex++, szServerId, &cbServerId)) + { + cbServerId = sizeof(szServerId); + // we have an entry that MIGHT be a server, but check to see if it really is one + if(WD_GetServerConfig(szServerId, szServerRoot, &cbServerRoot)) + { + if(WD_IsServiceRunning(szServerId)) + nServerCount++; + } + cbServerRoot = sizeof(szServerRoot); + } + + return(nServerCount); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +DWORD WD_GetDefaultKeyValue(char *szServerName, char *szKeyName, DWORD dwDefault) +{ + HANDLE hSlapdKey = 0; + char szSlapdKey[MAX_LINE]; + DWORD dwValueType; + DWORD dwValue = dwDefault; + DWORD cbValue = sizeof(dwValue); + + // query registry key to figure out config directory + sprintf(szSlapdKey, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT, + szServerName); + if(RegOpenKey(HKEY_LOCAL_MACHINE, szSlapdKey, &hSlapdKey) == ERROR_SUCCESS) + { + RegQueryValueEx(hSlapdKey, szKeyName, NULL, &dwValueType, + (LPBYTE)&dwValue, &cbValue); + RegCloseKey(hSlapdKey); + } + + return(dwValue); +} + + +//--------------------------------------------------------------------------// +// figure out if we are running under Windows NT // +//--------------------------------------------------------------------------// +BOOL WD_IsWindowsNT(void) +{ + BOOL bReturn = FALSE; + OSVERSIONINFO osVersionInfo; + + osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if(GetVersionEx(&osVersionInfo)) + { + bReturn = (osVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); + } + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// figure out if we have enough physical memory to operate server // +//--------------------------------------------------------------------------// +BOOL WD_IsEnoughResources(void) +{ + BOOL bReturn = TRUE; + MEMORYSTATUS ms; + DWORD dwMinRamFree = 0; + DWORD dwMinRamTotal = DEFAULT_MINRAMTOTAL; + DWORD dwMinRamPerServer = DEFAULT_MINRAMPERSERVER; + + dwMinRamFree = WD_GetDefaultKeyValue(gszServerName, MINRAMFREE_KEY, DEFAULT_MINRAMFREE); + dwMinRamTotal = WD_GetDefaultKeyValue(gszServerName, MINRAMTOTAL_KEY, DEFAULT_MINRAMTOTAL); + dwMinRamPerServer = WD_GetDefaultKeyValue(gszServerName, MINRAMPERSERVER_KEY, DEFAULT_MINRAMPERSERVER); + + ZeroMemory((PVOID)&ms, sizeof(ms)); + GlobalMemoryStatus(&ms); + + if((ms.dwTotalPhys < (dwMinRamTotal * 1024)) || (ms.dwAvailPhys < (dwMinRamFree * 1024))) + bReturn = FALSE; + + if(ms.dwTotalPhys < (WD_GetRunningServerCount() * dwMinRamPerServer * 1024)) + bReturn = FALSE; + + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// write error to EventLog service // +//--------------------------------------------------------------------------// +BOOL WD_SysLog(WORD fwEventType, DWORD IDEvent, char *szData) +{ + BOOL bReturn = FALSE; + HANDLE hEventSource; + WORD fwCategory = 0; // event category + PSID pUserSid = NULL; // user security identifier (optional) + WORD cStrings = 1; // number of strings to merge with message + DWORD cbData = 0; // size of binary data, in bytes + LPCTSTR lpszStrings[64]; // array of strings to merge with message + LPVOID lpvData = 0; // address of binary data + + hEventSource = RegisterEventSource(NULL, TEXT(EVENTLOG_APPNAME)); + if( hEventSource != NULL) + { + lpszStrings[0] = (LPCTSTR)gszServerName; + if(szData != NULL) + { + lpszStrings[1] = (LPCTSTR)szData; + cStrings++; + } + + bReturn = ReportEvent(hEventSource, fwEventType, fwCategory, + IDEvent, pUserSid, cStrings, cbData, + lpszStrings, lpvData); + DeregisterEventSource(hEventSource); + } + + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// converts '/' chars to '\' // +//--------------------------------------------------------------------------// +void WD_UnixToDosPath(char *szText) +{ + if(szText) + { + while(*szText) + { + if(*szText == '/') + + *szText = '\\'; + szText++; + } + } +} + + + +//--------------------------------------------------------------------------// +// calc szServerRoot given szServerConfig, and store szServerRoot in // +// SLAPD_ROOT environment variable. // +//--------------------------------------------------------------------------// +BOOL WD_GetServerRoot(char *szServerRoot, char *szServerConfig) +{ + char szTemp[MAX_LINE], szServerRootEnvVar[MAX_LINE]; + BOOL bReturn = FALSE; + char *szChar = NULL; + + strcpy(szTemp, szServerConfig); + // szTemp should be something like c:\navgold\server\slapd-kennedy\config + if(szChar = strrchr(szTemp,'\\')) + { + *szChar = 0; + // szTemp should be c:\navgold\server\slapd-kennedy + if(szChar = strrchr(szTemp, '\\')) + { + *szChar = 0; + // szTemp should be c:\navgold\server + strcpy( szServerRoot, szTemp ); + wsprintf(szServerRootEnvVar, "%s=%s", SLAPD_ROOT, szTemp); + putenv(szServerRootEnvVar); + bReturn = TRUE; + } + } + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// calc szServerConfig given szServerName // +//--------------------------------------------------------------------------// +BOOL WD_GetConfigFromRegistry(char *szServerConfig, char *szServerName) +{ + BOOL bReturn = FALSE; + HANDLE hSlapdKey = 0; + char szSlapdKey[MAX_LINE]; + DWORD dwValueType; + char szValueString[MAX_LINE]; + DWORD cbValueString = sizeof(szValueString); + DWORD dwResult = 0; + + // query registry key to figure out config directory + sprintf(szSlapdKey, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT, + szServerName); + + dwResult = RegOpenKey(HKEY_LOCAL_MACHINE, szSlapdKey, &hSlapdKey); + if(dwResult != ERROR_SUCCESS) + { + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_REGISTRY, szSlapdKey); + return(bReturn); + } + + dwResult = RegQueryValueEx(hSlapdKey, VALUE_CONFIG_PATH, NULL, + &dwValueType, szValueString, &cbValueString); + if(dwResult != ERROR_SUCCESS) + { + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_REGISTRY, szSlapdKey); + } + else + { + strcpy(szServerConfig, szValueString); + WD_UnixToDosPath(szServerConfig); + WD_GetServerRoot(gszServerRoot, szServerConfig); + bReturn = TRUE; + } + RegCloseKey(hSlapdKey); + return(bReturn); +} + + +//--------------------------------------------------------------------------// +// calc szServerConfig and szServerName given szCmdLine // +//--------------------------------------------------------------------------// +BOOL WD_GetConfigFromCmdline(char *szServerConfig, char *szServerName, char *szCmdLine) +{ + BOOL bReturn = FALSE; + char *szChar = NULL; + + if(!szCmdLine || !(strcmp(szCmdLine, "")) ) + { + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_BADCMDLINE, szCmdLine); + return(bReturn); + } + + strcpy(szServerConfig, szCmdLine); + WD_UnixToDosPath(szCmdLine); + WD_GetServerRoot(gszServerRoot, szCmdLine); + + // szCmdLine should be something like c:\navgold\server\slapd-kennedy\config + if(szChar = strrchr(szCmdLine, '\\')) + { + *szChar = 0; + // szCmdLine should be c:\navgold\server\slapd-kennedy + if(szChar = strrchr(szCmdLine, '\\')) + { + szChar++; + // szChar should point to slapd-kennedy + strcpy(szServerName, szChar); + WD_GetConfigFromRegistry(szServerConfig, szServerName); + bReturn = TRUE; + + } + } + else + { + // szCmdLine should be something like slapd-kennedy + strcpy(szServerName, szCmdLine); + bReturn = WD_GetConfigFromRegistry(szServerConfig, szServerName); + } + + if(strlen(szServerName) == 0) + { + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_BADCMDLINE, szCmdLine); + bReturn = FALSE; + } + + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// parse server config file to see if it security is enabled // +//--------------------------------------------------------------------------// +BOOL WD_IsServerSecure(void) +{ + BOOL bReturn = FALSE; + char szFileName[MAX_PATH]; + char szText[MAX_LINE]; + char szSeperators[] = " \t\n"; + char *szTemp; + FILE *fh = NULL; + + sprintf(szFileName, "%s\\%s", gszServerConfig, SLAPD_CONF); + if(fh = fopen(szFileName, "r")) + { + while(!feof(fh)) + { + if(fgets(szText, sizeof(szText), fh)) + { + strlwr(szText); + + /* strtok() is not MT safe on Unix , but it is okay to call + here because this file is NT only and strtok() is MT safe on NT */ + + if(szTemp = strtok(szText, szSeperators)) + { + if(strcmp(szTemp, "security") == 0) + { + if(szTemp = strtok(NULL, szSeperators)) + { + if(strcmp(szTemp, "on") == 0) + bReturn = TRUE; + } + break; + } + } + } + } + fclose(fh); + } + + return(bReturn); +} + +//--------------------------------------------------------------------------// +// message proc window for app window // +//--------------------------------------------------------------------------// +LONG APIENTRY WD_MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam) +{ + switch(message) + { + case WM_CREATE: + break; + + case WM_CLOSE: + SetEvent(ghevWatchDogExit); + break; + + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case ID_SERVER_SHUTDOWN: + { + HANDLE hevShutdown = NULL; + char szShutdownEvent[MAX_LINE]; + + // shutdown web server, it should exit with 0, WatchDog won't restart it + sprintf(szShutdownEvent, "NS_%s", gszServerName); + hevShutdown = OpenEvent(EVENT_MODIFY_STATE, FALSE, szShutdownEvent); + if(hevShutdown) + { + SetEvent(hevShutdown); // try to exit gracefully + CLOSEHANDLE(hevShutdown); + } + break; + } + + case ID_SERVER_RESTART: + { + // shutdown web server, it should exit with 2, WatchDog will restart it + if(ghServerProcess) + { + CLOSEHANDLE(ghServerProcess); + TerminateProcess(ghServerProcess, 2); + } + break; + } + + case ID_SERVER_SUSPEND: + { + if(ghServerThread0) + SuspendThread(ghServerThread0); + break; + } + + case ID_SERVER_RESUME: + { + if(ghServerThread0) + ResumeThread(ghServerThread0); + break; + } + + case ID_FILE_EXIT: + PostMessage(hWnd, WM_CLOSE, 0, 0); + break; + } + break; + } + + default: + return(DefWindowProc(hWnd, message, wParam, lParam)); + } + return(0); +} + + + +//--------------------------------------------------------------------------// +// This window serves as an IPC method with the server process. It has // +// pointers in it's storage area that the server uses to access the SSL // +// password. Quite strange, but it works perfectly well. // +//--------------------------------------------------------------------------// +HWND WD_CreateWindow() +{ + HWND hWndMain = NULL; + WNDCLASS wc; + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)WD_MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(LONG) * 4; + wc.hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_LOGO)); + wc.hInstance = ghInstance; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = GetStockObject(GRAY_BRUSH); + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); + wc.lpszClassName = "slapd"; + + RegisterClass(&wc); // class may be registered if more than one instance + + hWndMain = CreateWindow( + wc.lpszClassName, /* See RegisterClass() call. */ + gszServerName, /* Text for window title bar. */ + WS_OVERLAPPEDWINDOW | /* Window style. */ + WS_POPUP, /* Window style. */ + CW_USEDEFAULT, /* Default horizontal position. */ + CW_USEDEFAULT, /* Default vertical position. */ + 320, /* Default width. */ + 0, /* Default height. */ + NULL, /* Overlapped windows have no parent. */ + NULL, /* Use the window class menu. */ + ghInstance, /* This instance owns this window. */ + NULL /* Pointer not needed. */ + ); + + if(hWndMain) + { +#ifdef SHOW_DEBUG_WINDOW + ShowWindow(hWndMain, SW_SHOWDEFAULT); +#else + ShowWindow(hWndMain, SW_HIDE); +#endif + UpdateWindow(hWndMain); + } + return hWndMain; +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +void WD_WindowThreadProc(LPDWORD lpdwParam) +{ + HANDLE hevWindowCreated = (HANDLE)lpdwParam; + MSG msg; + + // the ghWndMain global is used all over the place + ghWndMain = WD_CreateWindow(); + + // inform parent that window creation is complete because it is waiting on us + SetEvent(hevWindowCreated); + + if(ghWndMain) + { + while(GetMessage(&msg, ghWndMain, 0, 0) == TRUE) + { + TranslateMessage(&msg); // Translates virtual key codes + DispatchMessage(&msg); // Dispatches message to window + } + } +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +void WD_PasswordThreadProc(LPDWORD lpdwParam) +{ + // app window must be created sometime during initialization + if(ghWndMain) + { + ZeroMemory(gszPassword, sizeof(gszPassword)); + SetWindowLong(ghWndMain, GWL_PASSWORD_ADDR, (LONG)gszPassword); + SetWindowLong(ghWndMain, GWL_PASSWORD_LENGTH, (LONG)0); + } +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL WD_StartServer(PROCESS_INFORMATION *pi) +{ + BOOL bReturn = FALSE; + char szCmdLine[MAX_LINE]; + char szServerPath[MAX_PATH]; + char szInstancePath [MAX_PATH]; + char *szChar; + STARTUPINFO sui; + DWORD fdwCreate = DETACHED_PROCESS; /* flags for CreateProcess */ + int i; + char *posfile; + UNALIGNED long *posfhnd; + + if(!WD_IsEnoughResources()) + { + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_STRING, MSG_RESOURCES); + gdwServiceError = ERROR_SERVICE_NOT_ACTIVE; + return(FALSE); + } + + strcpy(szServerPath, gszServerConfig); + WD_UnixToDosPath(szServerPath); + + // szServerPath should now be something similar to + // c:\navgold\server\slapd-kennedy\config + if(szChar = strrchr(szServerPath, '\\')) + { + *szChar = 0; + strcpy (szInstancePath, szServerPath); + if(szChar = strrchr(szServerPath, '\\')) + { + *szChar = 0; + } + } + + // For Directory Server, service-name is defined as slapd.exe, + // in ldapserver/include/nt/regpargms.h + sprintf( szCmdLine, "%s\\bin\\%s\\server\\%s -D \"%s\"", szServerPath, + PRODUCT_NAME, SERVICE_EXE, szInstancePath ); + // szCmdLine ex: c:\navgold\server\bin\slapd\slapd.exe + // -f c:\navgold\server\slapd-kennedy\config + + memset(&sui,0,sizeof(sui)); + sui.cb = sizeof(STARTUPINFO); + + /* All of this, to CreateProcess(), allows us to run a console + app (slapd.exe) from the service (ns-slapd.exe), without a + new console being opened for the app. + See dospawn.c in the crt src for more details. + */ + sui.cbReserved2 = (WORD)(sizeof( int ) + (3 * + (sizeof( char ) + sizeof( long )))); + + sui.lpReserved2 = calloc( sui.cbReserved2, 1 ); + + *((UNALIGNED int *)(sui.lpReserved2)) = 3; + + posfile = (char *)(sui.lpReserved2 + sizeof( int )); + + posfhnd = (UNALIGNED long *)(sui.lpReserved2 + sizeof( int ) + + (3 * sizeof( char ))); + + for ( i = 0, + posfile = (char *)(sui.lpReserved2 + sizeof( int )), + posfhnd = (UNALIGNED long *)(sui.lpReserved2 + sizeof( int ) + + (3 * sizeof( char ))) ; + i < 3 ; + i++, posfile++, posfhnd++ ) + { + *posfile = 0; + *posfhnd = (long)INVALID_HANDLE_VALUE; + } + + fdwCreate |= CREATE_SUSPENDED; + bReturn = CreateProcess(NULL, szCmdLine, NULL, NULL, + TRUE, fdwCreate, NULL, NULL, &sui, pi ); + if(bReturn) + { + ghServerProcess = pi->hProcess; // used by app window + ghServerThread0 = pi->hThread; // used by app window + if(DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), + pi->hProcess, (LPHANDLE)&ghDuplicateProcess, + (DWORD)PROCESS_VM_READ | PROCESS_VM_WRITE | + PROCESS_ALL_ACCESS, FALSE, (DWORD)0)) + { + SetWindowLong(ghWndMain, GWL_PROCESS_HANDLE, + (LONG)ghDuplicateProcess); + } + ResumeThread(pi->hThread); + } + else + { + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_STARTFAILED, szCmdLine); + } + + free( sui.lpReserved2 ); + + return(bReturn); +} + + + + +//------------------------------------------------------z--------------------// +// // +//--------------------------------------------------------------------------// +BOOL WD_CreatePasswordThread(void) +{ + #define NUM_WAIT_OBJECTS 2 + enum { CHILD_PROCESS, EXIT_EVENT }; + + BOOL bReturn = FALSE; + HANDLE lphObject[NUM_WAIT_OBJECTS]; + HANDLE hPasswordThread; + DWORD dwThreadID; + DWORD dwResult; + + lphObject[EXIT_EVENT] = ghevWatchDogExit; + + hPasswordThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, + (LPTHREAD_START_ROUTINE)WD_PasswordThreadProc, NULL, 0, &dwThreadID); + if(hPasswordThread) + { + lphObject[CHILD_PROCESS] = hPasswordThread; + dwResult = WaitForMultipleObjects(NUM_WAIT_OBJECTS, lphObject, FALSE, INFINITE); + CLOSEHANDLE(hPasswordThread); + if(dwResult == WAIT_OBJECT_0 + EXIT_EVENT) // user stopped service + { + EndDialog(ghdlgPassword, 1); + } + bReturn = TRUE; + } + else + { + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_BADPASSWORD, NULL); + } + return(bReturn); +} + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL WD_CreateWindowThread(void) +{ + BOOL bReturn = FALSE; + DWORD dwThreadID; + HANDLE hWindowThread; + HANDLE hevWindowCreated = NULL; + + if(hevWindowCreated = CreateEvent(NULL, FALSE, FALSE, NULL)) + { + if(hWindowThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, + (LPTHREAD_START_ROUTINE)WD_WindowThreadProc, (LPVOID)hevWindowCreated, 0, &dwThreadID)) + { + // make sure ghHwndMain is created otherwise + // SetWindowLong(ghWndMain) will fail in other threads + WaitForSingleObject(hevWindowCreated, INFINITE); + CLOSEHANDLE(hWindowThread); + bReturn = TRUE; + } + } + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL WD_CreateCronThread(HANDLE hevWatchDogExit) +{ + BOOL bReturn = FALSE; + DWORD dwThreadID = 0; + HANDLE hWindowThread = NULL; +#if 0 + if(hWindowThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, + (LPTHREAD_START_ROUTINE)CRON_ThreadProc, (LPVOID)hevWatchDogExit, 0, &dwThreadID)) + { + CLOSEHANDLE(hWindowThread); + bReturn = TRUE; + } +#endif + return(bReturn); +} + + +//--------------------------------------------------------------------------// +// signals event create by SNMP agent for notification of server shutdown // +//--------------------------------------------------------------------------// +#if 0 +BOOL WS_SendSNMPTrapSignal(void) +{ + BOOL bReturn = FALSE; + HANDLE hevShutdown = NULL; + char szShutdownEvent[MAX_LINE]; + + sprintf(szShutdownEvent, NSEV_SNMPTRAP_HTTP); + hevShutdown = OpenEvent(EVENT_MODIFY_STATE, FALSE, szShutdownEvent); + if(hevShutdown) + { + SetEvent(hevShutdown); + CLOSEHANDLE(hevShutdown); + bReturn = TRUE; + } + return(bReturn); +} +#endif + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL WD_MonitorServer(void) +{ + #define NUM_WAIT_OBJECTS 2 + enum { SERVER_PROCESS, WATCHDOG_EXIT }; + + BOOL bReturn = FALSE; + HANDLE lphObject[NUM_WAIT_OBJECTS]; + DWORD dwResult = 0; + DWORD dwExitCode = 0; + PROCESS_INFORMATION pi; + HANDLE hevServerDone = NULL; + char szServerDoneEvent[MAX_LINE]; + char szText[MAX_LINE]; + DWORD dwTickCount = 0; + + lphObject[WATCHDOG_EXIT] = ghevWatchDogExit; + + while(WD_StartServer(&pi)) + { + dwTickCount = GetTickCount(); + lphObject[SERVER_PROCESS] = pi.hProcess; + dwResult = WaitForMultipleObjects(NUM_WAIT_OBJECTS, lphObject, FALSE, INFINITE); + + //WS_SendSNMPTrapSignal(); + + if(dwResult == WAIT_OBJECT_0 + WATCHDOG_EXIT) + { + // shutdown web server + //CLOSEHANDLE(pi.hProcess); // XXXahakim close them after TerminateProcess() + //CLOSEHANDLE(pi.hThread); + sprintf(szServerDoneEvent, "NS_%s", gszServerName); + hevServerDone = OpenEvent(EVENT_MODIFY_STATE, FALSE, szServerDoneEvent); + if(hevServerDone) + { + SetEvent(hevServerDone); // try to exit gracefully + CLOSEHANDLE(hevServerDone); + WaitForSingleObject(lphObject[SERVER_PROCESS], 1000 * DEFAULT_KILL_TIME); + } + // but just in case it's still alive, swat it again, harder! + TerminateProcess(lphObject[SERVER_PROCESS], 1); + CLOSEHANDLE(pi.hProcess); // XXXahakim moved from above 03/06/96 + CLOSEHANDLE(pi.hThread); + bReturn = TRUE; + } + else + if(dwResult == WAIT_OBJECT_0 + SERVER_PROCESS) + { + // why did web server shutdown? + // GetExitCodeProcess(lphObject[SERVER_PROCESS], &dwExitCode); + // if(dwExitCode != 0) + // checking the exit code is bogus because a crashed process can return + // anything, including 0, so we use another method to determine if the + // server shutdown legitimately, which is similar to how unix works + // according to robm. + + // check to see if a specified amount of time has elapsed since the server + // started. If it's "infant mortality" don't bother restarting it + // because chances are it will continue to fail (such as when the password + // is bad, or if there is some other severe startup problem) + if(GetTickCount() - dwTickCount > 1000 * WD_GetDefaultKeyValue(gszServerName, MORTALITY_KEY, DEFAULT_MORTALITY_TIME)) + { + sprintf(szText, "%d", dwExitCode); + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_RESTART, szText); + CLOSEHANDLE(pi.hProcess); + CLOSEHANDLE(pi.hThread); + CLOSEHANDLE(ghDuplicateProcess); + Sleep(DEFAULT_RESTART_TIME * 1000); + continue; + } + // server closed legitimately + else + bReturn = TRUE; + } + CLOSEHANDLE(pi.hProcess); + CLOSEHANDLE(pi.hThread); + CLOSEHANDLE(ghDuplicateProcess); + break; + } + + return(bReturn); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +BOOL WD_SetServiceStatus(DWORD dwCurrentState, DWORD dwError) +{ + BOOL bReturn = FALSE; + SERVICE_STATUS ssStatus; + + if(gsshServiceStatus) + { + gdwLastStatus = dwCurrentState; + ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ssStatus.dwCurrentState = dwCurrentState; + ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_PAUSE_CONTINUE | + SERVICE_ACCEPT_SHUTDOWN; + ssStatus.dwWin32ExitCode = dwError; + ssStatus.dwServiceSpecificExitCode = (NO_ERROR ? 0 : 1); + ssStatus.dwCheckPoint = 0; + ssStatus.dwWaitHint = (1000 * ((dwCurrentState==SERVICE_STOP_PENDING)?600:DEFAULT_KILL_TIME + 1)); + bReturn = SetServiceStatus(gsshServiceStatus, &ssStatus); + } + return(FALSE); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +VOID WINAPI WD_ServiceHandler(DWORD fdwControl) +{ + switch(fdwControl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + WD_SetServiceStatus(SERVICE_STOP_PENDING, gdwServiceError); + SetEvent(ghevWatchDogExit); + return; + + case SERVICE_CONTROL_PAUSE: + if(ghServerThread0) + { + WD_SetServiceStatus(SERVICE_PAUSE_PENDING, gdwServiceError); + SuspendThread(ghServerThread0); + WD_SetServiceStatus(SERVICE_PAUSED, gdwServiceError); + return; + } + break; + + case SERVICE_CONTROL_CONTINUE: + if(ghServerThread0) + { + WD_SetServiceStatus(SERVICE_CONTINUE_PENDING, gdwServiceError); + ResumeThread(ghServerThread0); + WD_SetServiceStatus(SERVICE_RUNNING, gdwServiceError); + return; + } + break; + + case SERVICE_CONTROL_INTERROGATE: + WD_SetServiceStatus(gdwLastStatus, gdwServiceError); + return; + + default: + WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_RESTART, "unknown service event"); + return; + } + WD_SetServiceStatus(SERVICE_RUNNING, gdwServiceError); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +VOID WD_ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) +{ + BOOL bOkToProceed = TRUE; + // if SCM calls us lpszArgv will not be NULL + BOOL bIsService = (lpszArgv != NULL); + + // register our custom control handler to handle shutdown + ghWdogProcess = GetCurrentProcess(); + SetConsoleCtrlHandler(WD_ControlHandler, TRUE); + + if(bIsService) + { + gsshServiceStatus = RegisterServiceCtrlHandler(lpszArgv[0], + (LPHANDLER_FUNCTION)WD_ServiceHandler); + bOkToProceed = (gsshServiceStatus != (SERVICE_STATUS_HANDLE)NULL); + if(bOkToProceed) + { + strcpy(gszServerName, lpszArgv[0]); + bOkToProceed = WD_GetConfigFromRegistry(gszServerConfig, + gszServerName); + } + } + + WD_SetServiceStatus(SERVICE_START_PENDING, gdwServiceError); + + if(bOkToProceed) + { + if(ghevWatchDogExit = CreateEvent(NULL, TRUE, FALSE, gszServerName)) + { + WD_SetServiceStatus(SERVICE_RUNNING, gdwServiceError); + WD_CreateWindowThread(); +#if 0 + WD_CreateCronThread(ghevWatchDogExit); +#endif + + if(WD_IsServerSecure()) + { + bOkToProceed = WD_CreatePasswordThread(); + } + + if(bOkToProceed) + { + WD_MonitorServer(); + } + CLOSEHANDLE(ghevWatchDogExit); + } + } + WD_SetServiceStatus(SERVICE_STOPPED, gdwServiceError); +} + + + +//--------------------------------------------------------------------------// +// // +//--------------------------------------------------------------------------// +WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, + int nCmdShow) +{ + SERVICE_TABLE_ENTRY steServiceTable[2]; + +#ifdef PUMPKIN_HOUR + if(time(NULL) > (PUMPKIN_HOUR - 10)) + { + char szMessage[256]; + sprintf( szMessage, " ** This beta software has expired **\n"); + MessageBox(GetDesktopWindow(), szMessage, + DS_NAME_FULL_VERSION, MB_ICONEXCLAMATION | MB_OK); + exit(1); + } +#endif + + if(!hPrevInstance) // other instances of app running? + { + ghInstance = hInstance; + memset(gszPassword, 0, sizeof(gszPassword)); + memset(gszServerConfig, 0, sizeof(gszServerConfig)); + memset(gszServerName, 0, sizeof(gszServerName)); + if(WD_IsWindowsNT() && (lpCmdLine) && (strlen(lpCmdLine) == 0)) + { + // run as service + steServiceTable[0].lpServiceName = TEXT(PRODUCT_NAME); + steServiceTable[0].lpServiceProc = + (LPSERVICE_MAIN_FUNCTION)WD_ServiceMain; + steServiceTable[1].lpServiceName = NULL; + steServiceTable[1].lpServiceProc = NULL; + StartServiceCtrlDispatcher(steServiceTable); + } + else + { + // run as application + if(WD_GetConfigFromCmdline(gszServerConfig, + gszServerName, lpCmdLine)) + { + WD_ServiceMain(0, (LPTSTR *)NULL); + } + } + } + return(FALSE); +} |