shell bypass 403
/* ========================================================================
* Copyright 1988-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* ========================================================================
*/
/*
* Program: NT environment routines
*
* Author: Mark Crispin
* UW Technology
* University of Washington
* Seattle, WA 98195
* Internet: MRC@Washington.EDU
*
* Date: 1 August 1988
* Last Edited: 15 February 2008
*/
static char *myUserName = NIL; /* user name */
static char *myLocalHost = NIL; /* local host name */
static char *myHomeDir = NIL; /* home directory name */
static char *myNewsrc = NIL; /* newsrc file name */
static char *sysInbox = NIL; /* system inbox name */
static long list_max_level = 5; /* maximum level of list recursion */
/* block environment init */
static short block_env_init = NIL;
static short no822tztext = NIL; /* disable RFC [2]822 timezone text */
/* home namespace */
static NAMESPACE nshome = {"",'\\',NIL,NIL};
/* UNIX other user namespace */
static NAMESPACE nsother = {"#user.",'\\',NIL,NIL};
/* namespace list */
static NAMESPACE *nslist[3] = {&nshome,&nsother,NIL};
static long alarm_countdown = 0;/* alarm count down */
static void (*alarm_rang) (); /* alarm interrupt function */
static unsigned int rndm = 0; /* initial `random' number */
static int server_nli = 0; /* server and not logged in */
static int logtry = 3; /* number of login tries */
/* block notification */
static blocknotify_t mailblocknotify = mm_blocknotify;
/* callback to get username */
static userprompt_t mailusername = NIL;
static long is_nt = -1; /* T if NT, NIL if not NT, -1 unknown */
static HINSTANCE netapi = NIL;
typedef NET_API_STATUS (CALLBACK *GETINFO) (LPCWSTR,LPCWSTR,DWORD,LPBYTE *);
static GETINFO getinfo = NIL;
#include "write.c" /* include safe writing routines */
#include "pmatch.c" /* include wildcard pattern matcher */
/* Get all authenticators */
#include "auths.c"
/* Environment manipulate parameters
* Accepts: function code
* function-dependent value
* Returns: function-dependent return value
*/
void *env_parameters (long function,void *value)
{
void *ret = NIL;
switch ((int) function) {
case GET_NAMESPACE:
ret = (void *) nslist;
break;
case SET_USERPROMPT :
mailusername = (userprompt_t) value;
case GET_USERPROMPT :
ret = (void *) mailusername;
break;
case SET_HOMEDIR:
if (myHomeDir) fs_give ((void **) &myHomeDir);
myHomeDir = cpystr ((char *) value);
case GET_HOMEDIR:
ret = (void *) myHomeDir;
break;
case SET_LOCALHOST:
myLocalHost = cpystr ((char *) value);
case GET_LOCALHOST:
if (myLocalHost) fs_give ((void **) &myLocalHost);
ret = (void *) myLocalHost;
break;
case SET_NEWSRC:
if (myNewsrc) fs_give ((void **) &myNewsrc);
myNewsrc = cpystr ((char *) value);
case GET_NEWSRC:
if (!myNewsrc) { /* set news file name if not defined */
char tmp[MAILTMPLEN];
sprintf (tmp,"%s\\NEWSRC",myhomedir ());
myNewsrc = cpystr (tmp);
}
ret = (void *) myNewsrc;
break;
case SET_SYSINBOX:
if (sysInbox) fs_give ((void **) &sysInbox);
sysInbox = cpystr ((char *) value);
case GET_SYSINBOX:
ret = (void *) sysInbox;
break;
case SET_LISTMAXLEVEL:
list_max_level = (long) value;
case GET_LISTMAXLEVEL:
ret = (void *) list_max_level;
break;
case SET_DISABLE822TZTEXT:
no822tztext = value ? T : NIL;
case GET_DISABLE822TZTEXT:
ret = (void *) (no822tztext ? VOIDT : NIL);
break;
case SET_BLOCKENVINIT:
block_env_init = value ? T : NIL;
case GET_BLOCKENVINIT:
ret = (void *) (block_env_init ? VOIDT : NIL);
break;
case SET_BLOCKNOTIFY:
mailblocknotify = (blocknotify_t) value;
case GET_BLOCKNOTIFY:
ret = (void *) mailblocknotify;
break;
}
return ret;
}
/* Write current time
* Accepts: destination string
* optional format of day-of-week prefix
* format of date and time
* flag whether to append symbolic timezone
*/
static void do_date (char *date,char *prefix,char *fmt,int suffix)
{
time_t tn = time (0);
struct tm *t = gmtime (&tn);
int zone = t->tm_hour * 60 + t->tm_min;
int julian = t->tm_yday;
t = localtime (&tn); /* get local time now */
/* minus UTC minutes since midnight */
zone = t->tm_hour * 60 + t->tm_min - zone;
/* julian can be one of:
* 36x local time is December 31, UTC is January 1, offset -24 hours
* 1 local time is 1 day ahead of UTC, offset +24 hours
* 0 local time is same day as UTC, no offset
* -1 local time is 1 day behind UTC, offset -24 hours
* -36x local time is January 1, UTC is December 31, offset +24 hours
*/
if (julian = t->tm_yday -julian)
zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
if (prefix) { /* want day of week? */
sprintf (date,prefix,days[t->tm_wday]);
date += strlen (date); /* make next sprintf append */
}
/* output the date */
sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
if (suffix) { /* append timezone suffix if desired */
char *tz;
tzset (); /* get timezone from TZ environment stuff */
tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
if (tz && tz[0]) {
char *s;
for (s = tz; *s; s++) if (*s & 0x80) return;
sprintf (date + strlen (date)," (%.50s)",tz);
}
}
}
/* Write current time in RFC 822 format
* Accepts: destination string
*/
void rfc822_date (char *date)
{
do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
no822tztext ? NIL : T);
}
/* Write current time in fixed-width RFC 822 format
* Accepts: destination string
*/
void rfc822_fixed_date (char *date)
{
do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
}
/* Write current time in internal format
* Accepts: destination string
*/
void internal_date (char *date)
{
do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
}
/* Return random number
*/
long random (void)
{
if (!rndm) srand (rndm = (unsigned) time (0L));
return (long) rand ();
}
/* Set alarm timer
* Accepts: new value
* Returns: old alarm value
*/
long alarm (long seconds)
{
long ret = alarm_countdown;
alarm_countdown = seconds;
return ret;
}
/* The clock ticked
*/
void CALLBACK clock_ticked (UINT IDEvent,UINT uReserved,DWORD dwUser,
DWORD dwReserved1,DWORD dwReserved2)
{
if (alarm_rang && !--alarm_countdown) (*alarm_rang) ();
}
/* Initialize server
* Accepts: server name for syslog or NIL
* /etc/services service name or NIL
* alternate /etc/services service name or NIL
* clock interrupt handler
* kiss-of-death interrupt handler
* hangup interrupt handler
* termination interrupt handler
*/
void server_init (char *server,char *service,char *sslservice,
void *clkint,void *kodint,void *hupint,void *trmint,
void *staint)
{
if (!check_nt ()) {
if (!auth_md5.server) fatal ("Can't run on Windows without MD5 database");
server_nli = T; /* Windows server not logged in */
}
/* only do this if for init call */
if (server && service && sslservice) {
long port;
struct servent *sv;
/* set server name in syslog */
openlog (server,LOG_PID,LOG_MAIL);
fclose (stderr); /* possibly save a process ID */
/* Use SSL if SSL service, or if server starts with "s" and not service */
if (((port = tcp_serverport ()) >= 0)) {
if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
else if ((sv = getservbyname (sslservice,"tcp")) &&
(port == ntohs (sv->s_port))) {
syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
tcp_clientaddr ());
ssl_server_init (server);
}
else { /* not service or SSL service port */
syslog (LOG_DEBUG,"port %ld service init from %s",port,
tcp_clientaddr ());
if (*server == 's') ssl_server_init (server);
}
}
/* make sure stdout does binary */
setmode (fileno (stdin),O_BINARY);
setmode (fileno (stdout),O_BINARY);
}
alarm_rang = clkint; /* note the clock interrupt */
timeBeginPeriod (1000); /* set the timer interval */
timeSetEvent (1000,1000,clock_ticked,NIL,TIME_PERIODIC);
}
/* Wait for stdin input
* Accepts: timeout in seconds
* Returns: T if have input on stdin, else NIL
*/
long server_input_wait (long seconds)
{
fd_set rfd,efd;
struct timeval tmo;
FD_ZERO (&rfd);
FD_ZERO (&efd);
FD_SET (0,&rfd);
FD_SET (0,&efd);
tmo.tv_sec = seconds; tmo.tv_usec = 0;
return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
}
/* Server log in
* Accepts: user name string
* password string
* authenticating user name string
* argument count
* argument vector
* Returns: T if password validated, NIL otherwise
*/
static int gotprivs = NIL; /* once-only flag to grab privileges */
long server_login (char *user,char *pass,char *authuser,int argc,char *argv[])
{
HANDLE hdl;
LUID tcbpriv;
TOKEN_PRIVILEGES tkp;
char *s;
/* need to get privileges? */
if (!gotprivs++ && check_nt ()) {
/* hack for inetlisn */
if (argc >= 2) myClientHost = argv[1];
/* get process token and TCB priv value */
if (!(OpenProcessToken (GetCurrentProcess (),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hdl) &&
LookupPrivilegeValue ((LPSTR) NIL,SE_TCB_NAME,&tcbpriv)))
return NIL;
tkp.PrivilegeCount = 1; /* want to enable this privilege */
tkp.Privileges[0].Luid = tcbpriv;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
/* enable it */
AdjustTokenPrivileges (hdl,NIL,&tkp,sizeof (TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NIL,(PDWORD) NIL);
/* make sure it won */
if (GetLastError() != ERROR_SUCCESS) return NIL;
}
/* cretins still haven't given up */
if ((strlen (user) >= MAILTMPLEN) ||
(authuser && (strlen (authuser) >= MAILTMPLEN)))
syslog (LOG_ALERT,"SYSTEM BREAK-IN ATTEMPT, host=%.80s",tcp_clienthost ());
else if (logtry > 0) { /* still have available logins? */
/* authentication user not supported */
if (authuser && *authuser && compare_cstring (authuser,user))
mm_log ("Authentication id must match authorization id",ERROR);
if (check_nt ()) { /* NT: authserver_login() call not supported */
if (!pass) mm_log ("Unsupported authentication mechanism",ERROR);
else if (( /* try to login and impersonate the guy */
#ifdef LOGIN32_LOGON_NETWORK
LogonUser (user,".",pass,LOGON32_LOGON_NETWORK,
LOGON32_PROVIDER_DEFAULT,&hdl) ||
#endif
LogonUser (user,".",pass,LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,&hdl) ||
LogonUser (user,".",pass,LOGON32_LOGON_BATCH,
LOGON32_PROVIDER_DEFAULT,&hdl) ||
LogonUser (user,".",pass,LOGON32_LOGON_SERVICE,
LOGON32_PROVIDER_DEFAULT,&hdl)) &&
ImpersonateLoggedOnUser (hdl)) return env_init (user,NIL);
}
else { /* Win9x: done if from authserver_login() */
if (!pass) server_nli = NIL;
/* otherwise check MD5 database */
else if (s = auth_md5_pwd (user)) {
/* change NLI state based on pwd match */
server_nli = strcmp (s,pass);
memset (s,0,strlen (s));/* erase sensitive information */
fs_give ((void **) &s); /* flush erased password */
}
/* success if no longer NLI */
if (!server_nli) return env_init (user,NIL);
}
}
s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts";
/* note the failure in the syslog */
syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ());
sleep (3); /* slow down possible cracker */
return NIL;
}
/* Authenticated server log in
* Accepts: user name string
* authentication user name string
* argument count
* argument vector
* Returns: T if password validated, NIL otherwise
*/
long authserver_login (char *user,char *authuser,int argc,char *argv[])
{
return server_login (user,NIL,authuser,argc,argv);
}
/* Log in as anonymous daemon
* Accepts: argument count
* argument vector
* Returns: T if successful, NIL if error
*/
long anonymous_login (int argc,char *argv[])
{
return server_login ("Guest",NIL,NIL,argc,argv);
}
/* Initialize environment
* Accepts: user name
* home directory, or NIL to use default
* Returns: T, always
*/
long env_init (char *user,char *home)
{
/* don't init if blocked */
if (block_env_init) return LONGT;
if (myUserName) fatal ("env_init called twice!");
myUserName = cpystr (user); /* remember user name */
if (!myHomeDir) /* only if home directory not set up yet */
myHomeDir = (home && *home) ? cpystr (home) : win_homedir (user);
return T;
}
/* Check if NT
* Returns: T if NT, NIL if Win9x
*/
int check_nt (void)
{
if (is_nt < 0) { /* not yet set up? */
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
GetVersionEx (&ver);
is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? T : NIL;
}
return is_nt;
}
/* Return Windows home directory
* Accepts: user name
* Returns: home directory
*/
char *win_homedir (char *user)
{
char *s,*t,tmp[MAILTMPLEN];
PUSER_INFO_1 ui;
/* Win9x default */
if (!check_nt ()) sprintf (tmp,"%s\\My Documents",defaultDrive ());
/* get from user info on NT */
else if ((netapi || (netapi = LoadLibrary ("netapi32.dll"))) &&
(getinfo ||
(getinfo = (GETINFO) GetProcAddress (netapi,"NetUserGetInfo"))) &&
MultiByteToWideChar (CP_ACP,0,user,strlen (user) + 1,
(WCHAR *) tmp,MAILTMPLEN) &&
!(*getinfo) (NIL,(LPWSTR) &tmp,1,(LPBYTE *) &ui) &&
WideCharToMultiByte (CP_ACP,0,ui->usri1_home_dir,-1,
tmp,MAILTMPLEN,NIL,NIL) && tmp[0]) {
/* make sure doesn't end with delimiter */
if ((*(s = tmp + strlen (tmp) - 1) == '\\') || (*s == '/')) *s = '\0';
}
/* no home dir, found Win2K user profile? */
else if ((s = getenv ("USERPROFILE")) && (t = strrchr (s,'\\'))) {
strncpy (tmp,s,t-s); /* copy up to user name */
sprintf (tmp+(t-s),"\\%.100s\\My Documents",user);
}
/* last resort NT default */
else sprintf (tmp,"%s\\users\\default",defaultDrive ());
return cpystr (tmp);
}
/* Return default drive
* Returns: default drive
*/
static char *defaultDrive (void)
{
char *s = getenv ("SystemDrive");
return (s && *s) ? s : "C:";
}
/* Return my user name
* Accepts: pointer to optional flags
* Returns: my user name
*/
char *myusername_full (unsigned long *flags)
{
UCHAR usr[MAILTMPLEN];
DWORD len = MAILTMPLEN;
char *user,*path,*d,*p,pth[MAILTMPLEN];
char *ret = "SYSTEM";
/* get user name if don't have it yet */
if (!myUserName && !server_nli &&
/* use callback, else logon name */
((mailusername && (user = (char *) (*mailusername) ())) ||
(GetUserName (usr,&len) && _stricmp (user = (char *) usr,"SYSTEM")))) {
if (block_env_init) { /* don't env_init if blocked */
if (flags) *flags = MU_LOGGEDIN;
return user;
}
/* try HOMEPATH, then HOME */
if (p = getenv ("HOMEPATH"))
sprintf (path = pth,"%s%s",
(d = getenv ("HOMEDRIVE")) ? d : defaultDrive (),p);
else if (!(path = getenv ("HOME")))
sprintf (path = pth,"%s\\My Documents",defaultDrive ());
/* make sure doesn't end with delimiter */
if ((*(p = path + strlen (path) -1) == '\\') || (*p == '/')) *p = '\0';
env_init (user,path); /* initialize environment */
}
if (myUserName) { /* logged in? */
if (flags) /* Guest is an anonymous user */
*flags = _stricmp (myUserName,"Guest") ? MU_LOGGEDIN : MU_ANONYMOUS;
ret = myUserName; /* return user name */
}
else if (flags) *flags = MU_NOTLOGGEDIN;
return ret;
}
/* Return my local host name
* Returns: my local host name
*/
char *mylocalhost (void)
{
if (!myLocalHost) {
char tmp[MAILTMPLEN];
if (!wsa_initted++) { /* init Windows Sockets */
WSADATA wsock;
if (WSAStartup (WINSOCK_VERSION,&wsock)) {
wsa_initted = 0;
return "random-pc"; /* try again later? */
}
}
myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
"random-pc" : tcp_canonical (tmp));
}
return myLocalHost;
}
/* Return my home directory name
* Returns: my home directory name
*/
char *myhomedir ()
{
if (!myHomeDir) myusername ();/* initialize if first time */
return myHomeDir ? myHomeDir : "";
}
/* Return system standard INBOX
* Accepts: buffer string
*/
char *sysinbox ()
{
char tmp[MAILTMPLEN];
if (!sysInbox) { /* initialize if first time */
if (check_nt ()) sprintf (tmp,MAILFILE,myUserName);
else sprintf (tmp,"%s\\INBOX",myhomedir ());
sysInbox = cpystr (tmp); /* system inbox is from mail spool */
}
return sysInbox;
}
/* Return mailbox directory name
* Accepts: destination buffer
* directory prefix
* name in directory
* Returns: file name or NIL if error
*/
char *mailboxdir (char *dst,char *dir,char *name)
{
char tmp[MAILTMPLEN];
if (dir || name) { /* if either argument provided */
if (dir) {
if (strlen (dir) > NETMAXMBX) return NIL;
strcpy (tmp,dir); /* write directory prefix */
}
else tmp[0] = '\0'; /* otherwise null string */
if (name) {
if (strlen (name) > NETMAXMBX) return NIL;
strcat (tmp,name); /* write name in directory */
}
/* validate name, return its name */
if (!mailboxfile (dst,tmp)) return NIL;
}
else strcpy (dst,myhomedir());/* no arguments, wants home directory */
return dst; /* return the name */
}
/* Return mailbox file name
* Accepts: destination buffer
* mailbox name
* Returns: file name or empty string for driver-selected INBOX or NIL if error
*/
char *mailboxfile (char *dst,char *name)
{
char homedev[3];
char *dir = myhomedir ();
if (dir[0] && isalpha (dir[0]) && (dir[1] == ':')) {
homedev[0] = dir[0]; /* copy home device */
homedev[1] = dir[1];
homedev[2] = '\0';
}
else homedev[0] = '\0'; /* ??no home device?? */
*dst = '\0'; /* default to empty string */
/* check for INBOX */
if (!compare_cstring (name,"INBOX"));
/* reject names with / */
else if (strchr (name,'/')) dst = NIL;
else switch (*name) {
case '#': /* namespace names */
if (((name[1] == 'u') || (name[1] == 'U')) &&
((name[2] == 's') || (name[2] == 'S')) &&
((name[3] == 'e') || (name[3] == 'E')) &&
((name[4] == 'r') || (name[4] == 'R')) && (name[5] == '.')) {
/* copy user name to destination buffer */
for (dir = dst,name += 6; *name && (*name != '\\'); *dir++ = *name++);
*dir++ = '\0'; /* tie off user name */
/* look up homedir for user name */
if (dir = win_homedir (dst)) {
/* build resulting name */
sprintf (dst,"%s\\%s",dir,name);
fs_give ((void **) &dir);
}
else dst = NIL;
}
else dst = NIL; /* unknown namespace name */
break;
case '\\': /* absolute path on default drive? */
sprintf (dst,"%s%s",homedev,name);
break;
default: /* any other name */
if (name[1] == ':') { /* some other drive? */
if (name[2] == '\\') strcpy (dst,name);
else sprintf (dst,"%c:\\%s",name[0],name+2);
}
/* build home-directory relative name */
else sprintf (dst,"%s\\%s",dir,name);
}
return dst; /* return it */
}
/* Lock file name
* Accepts: return buffer for file name
* file name
* locking to be placed on file if non-NIL
* Returns: file descriptor of lock or -1 if error
*/
int lockname (char *lock,char *fname,int op)
{
int ld;
char c,*s;
/* Win2K and Win98 have TEMP under windir */
if (!((s = lockdir (lock,getenv ("windir"),"TEMP")) ||
/* NT4, NT3.x and Win95 use one of these */
(s = lockdir (lock,getenv ("TEMP"),NIL)) ||
(s = lockdir (lock,getenv ("TMP"),NIL)) ||
(s = lockdir (lock,getenv ("TMPDIR"),NIL)) ||
/* try one of these */
(s = lockdir (lock,defaultDrive (),"WINNT\\TEMP")) ||
(s = lockdir (lock,defaultDrive (),"WINDOWS\\TEMP")) ||
/* C:\TEMP is last resort */
(s = lockdir (lock,defaultDrive (),"TEMP")))) {
mm_log ("Unable to find temporary directory",ERROR);
return -1;
}
/* generate file name */
while (c = *fname++) switch (c) {
case '/': case '\\': case ':':
*s++ = '!'; /* convert bad chars to ! */
break;
default:
*s++ = c;
break;
}
*s++ = c; /* tie off name */
/* get the lock */
if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
flock (ld,op); /* apply locking function */
return ld; /* return locking file descriptor */
}
/* Build lock directory, check to see if it exists
* Accepts: return buffer for lock directory
* first part of possible name
* optional second part
* Returns: pointer to end of buffer if buffer has a good name, else NIL
*/
char *lockdir (char *lock,char *first,char *last)
{
struct stat sbuf;
char c,*s;
if (first && *first) { /* first part must be non-NIL */
/* copy first part */
for (s = lock; c = *first++; *s++ = (c == '/') ? '\\' : c);
if (last && *last) { /* copy last part if specified */
/* write trailing \ in case not in first */
if (s[-1] != '\\') *s++ = '\\';
while (c = *last++) *s++ = (c == '/') ? '\\' : c;
}
if (s[-1] == '\\') --s; /* delete trailing \ if any */
*s = s[1] = '\0'; /* tie off name at this point */
if (!stat (lock,&sbuf)) { /* does the name exist? */
*s++ = '\\'; /* yes, reinstall trailing \ */
return s; /* return the name */
}
}
return NIL; /* failed */
}
/* Unlock file descriptor
* Accepts: file descriptor
* lock file name from lockfd()
*/
void unlockfd (int fd,char *lock)
{
flock (fd,LOCK_UN); /* unlock it */
close (fd); /* close it */
}
/* Determine default prototype stream to user
* Accepts: type (NIL for create, T for append)
* Returns: default prototype stream
*/
MAILSTREAM *default_proto (long type)
{
extern MAILSTREAM CREATEPROTO,APPENDPROTO;
return type ? &APPENDPROTO : &CREATEPROTO;
}
/* Default block notify routine
* Accepts: reason for calling
* data
* Returns: data
*/
void *mm_blocknotify (int reason,void *data)
{
void *ret = data;
switch (reason) {
case BLOCK_SENSITIVE: /* entering sensitive code */
ret = (void *) alarm (0);
break;
case BLOCK_NONSENSITIVE: /* exiting sensitive code */
if ((unsigned int) data) alarm ((unsigned int) data);
break;
default: /* ignore all other reasons */
break;
}
return ret;
}