/* * Mathematica license manager sentry. * * Mathematica license manager appears to be a single-threaded * application performing a single transaction at a time. This means * that clients that failed to complete transaction for some reason, * e.g. loss of network connectivity or even for a malicious purpose * (see http://www.securityfocus.com/archive/1/200462), shall prevent * other clients from obtaining the license. This module aggressively * times out transactions thus effectively avoids the denial of service. * * Then I enforce SO_REUSEADDR option so that the mathlm process can be * restarted instantly without having to wait till all TIME_WAIT-ed * connection disappear from netstat output. * * Then I mimic BSD signal semantic as apparently that's what Wolfram * programmers expect... Problem here is that Wolfram doesn't realize * that unlike BSD Solaris resets the disposition of signal to some * predefined default (can be coredump, exit or ignore depending on * signal) upon signal delivery and if one intends to keep handling the * signal, then one has to either reset handler in handler itself or * make sure SA_RESETHAND is not set. * * Then I map NULL pointer read-only so that printf("\"%s License * returned\"",NULL); doesn't cause segmentation violation. I don't * endorse this programming practice, just trying to survive... * * To compile (on Solaris): * * cc -O -D_REENTRANT -Kpic -G -z text -o mathlm.acl.so mathlm.acl.c * * To engage (on Solaris): * * env LD_PRELOAD=/some/place/mathlm.acl.so mathlm * * Other platforms on demand. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define TIMEOUT 500 /* 1/2 second */ #pragma init(setmeup) static void setmeup() { int fd; if ((fd=open("/dev/zero",O_RDONLY)) >= 0) mmap(NULL,sizeof(void*),PROT_READ,MAP_PRIVATE|MAP_FIXED,fd,0), close(fd); setsid(); } int _accept (int s, struct sockaddr *addr, void *addrlen); ssize_t _read (int fd, void *buf, size_t nbyte); ssize_t _write (int fd, const void *buf, size_t nbyte); int _close (int fd); int _setsockopt(int socket, int level, int option_name, const void *option_value, unsigned int option_len); static fd_set sockets_set; void (*signal (int sig,void (*handler)()))() { struct sigaction sa; void (*ret) (); sigaction (sig,NULL,&sa); sa.sa_flags &= ~SA_RESETHAND; sa.sa_flags |= SA_RESTART; ret = sa.sa_handler; sa.sa_handler = handler; sigaction (sig,&sa,NULL); return ret; } /* * Why on whole earth does mathlm set SO_REUSEADDR to 0? Why do we have * to wait till every closed connection in TIME_WAIT state times out? */ int setsockopt (int socket, int level, int option_name, const void *option_value, unsigned int option_len) { int on=1; if (level==SOL_SOCKET && option_name==SO_REUSEADDR) return _setsockopt (socket,level,option_name,(void *)&on,sizeof(on)); else return _setsockopt (socket,level,option_name,option_value,option_len); } /* * Compliment read and write on sockets returned by accept with timeout. */ ssize_t read(int fd, void *buf, size_t nbyte) { ssize_t ret=1; struct pollfd fds; if (fd<0 || !FD_ISSET (fd,&sockets_set)) return _read (fd,buf,nbyte); fds.fd = fd; fds.events = POLLIN; ret = poll (&fds,1,TIMEOUT); if (ret>0 && !(fds.revents&(POLLERR|POLLHUP))) ret = _read (fd,buf,nbyte); else { errno = EPIPE; shutdown (fd,0); } return ret; } ssize_t write(int fd, const void *buf, size_t nbyte) { ssize_t ret; struct pollfd fds; if (fd<0 || !FD_ISSET (fd,&sockets_set)) return _write (fd,buf,nbyte); fds.fd = fd; fds.events = POLLOUT; ret = poll (&fds,1,TIMEOUT); if (ret>0 && !(fds.revents&(POLLERR|POLLHUP))) ret = _write (fd,buf,nbyte); else { errno = EPIPE; shutdown (fd,0); } return ret; } /* * ... mark the socket in sockets_set */ int accept (int s, struct sockaddr *addr, void *addrlen) { int ret; struct sockaddr_in *_addr; if ((ret = _accept (s,addr,addrlen)) >= 0) FD_SET (ret,&sockets_set); return ret; } int close (int fd) { if (fd>=0) FD_CLR(fd,&sockets_set); return _close(fd); }