/* * Steven Schultz - sms@moe.2bsd.com * * @(#)ctimed.c 1.0 (2.11BSD) 1996/6/25 * * ctimed - the daemon that supports the ctime() and getpw*() stubs * in 'libcstubs.a'. */ #include <signal.h> #include <stdio.h> #include <setjmp.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/time.h> #include <pwd.h> #include <utmp.h> /* * These should probably be placed in an include file. If you add anything * here then you will also have to modify /usr/src/usr.lib/libstubs/stubs.c * (if for no other reason than to add the stub code). */ #define CTIME 1 #define ASCTIME 2 #define TZSET 3 #define LOCALTIME 4 #define GMTIME 5 #define OFFTIME 6 #define GETPWENT 7 #define GETPWNAM 8 #define GETPWUID 9 #define SETPASSENT 10 #define ENDPWENT 11 extern struct tm *offtime(); jmp_buf env; char *cp; char junk[256 + sizeof (struct passwd) + 4]; long off; time_t l; void timeout(), checkppid(); struct tm tmtmp, *tp; main() { register int i; register struct passwd *pw; struct itimerval it; u_char c, xxx; int len, tosslen; uid_t uid; signal(SIGPIPE, SIG_DFL); for (i = getdtablesize(); --i > 2; ) close(i); /* * Need a timer running while we disassociate from the control terminal * in case of a modem line which has lost carrier. */ timerclear(&it.it_interval); it.it_value.tv_sec = 5; it.it_value.tv_usec = 0; signal(SIGALRM, timeout); setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL); if (setjmp(env) == 0) { i = open("/dev/tty", 0); if (i >= 0) { ioctl(i, TIOCNOTTY, NULL); close(i); } } /* * Now start a timer with one minute refresh. In the signal service * routine, check the parent process id to see if this process has * been orphaned and if so exit. This is primarily aimed at removing * the 'ctimed' process left behind by 'sendmail's multi-fork startup * but may prove useful in preventing accumulation of 'ctimed' processes * in other circumstances as well. Normally this process is short * lived. */ it.it_interval.tv_sec = 60; it.it_interval.tv_usec = 0; it.it_value.tv_sec = 60; it.it_value.tv_usec = 0; signal(SIGALRM, checkppid); setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL); while (read(fileno(stdin), &c, 1) == 1) { switch (c) { case CTIME: l = 0L; getb(fileno(stdin), &l, sizeof l); cp = ctime(&l); write(fileno(stdout), cp, 26); break; case ASCTIME: getb(fileno(stdin), &tmtmp, sizeof tmtmp); cp = asctime(&tmtmp); write(fileno(stdout), cp, 26); break; case TZSET: (void) tzset(); break; case LOCALTIME: l = 0L; getb(fileno(stdin), &l, sizeof l); tp = localtime(&l); write(fileno(stdout), tp, sizeof (*tp)); strcpy(junk, tp->tm_zone); junk[24] = '\0'; write(fileno(stdout), junk, 24); break; case GMTIME: l = 0L; getb(fileno(stdin), &l, sizeof l); tp = gmtime(&l); write(fileno(stdout), tp, sizeof (*tp)); strcpy(junk, tp->tm_zone); junk[24] = '\0'; write(fileno(stdout), junk, 24); break; case OFFTIME: getb(fileno(stdin), &l, sizeof l); getb(fileno(stdin), &off, sizeof off); #ifdef __bsdi__ l += off; tp = localtime(&l); #else tp = offtime(&l, off); #endif write(fileno(stdout), tp, sizeof (*tp)); break; case GETPWENT: pw = getpwent(); do_pw(pw); break; case GETPWNAM: getb(fileno(stdin), &len, sizeof (int)); if (len > UT_NAMESIZE) { tosslen = len - UT_NAMESIZE; len = UT_NAMESIZE; } else tosslen = 0; getb(fileno(stdin), junk, len); for (;tosslen; tosslen--) getb(fileno(stdin), &xxx, 1); junk[len] = '\0'; pw = getpwnam(junk); do_pw(pw); break; case GETPWUID: getb(fileno(stdin), &uid, sizeof (uid_t)); pw = getpwuid(uid); do_pw(pw); break; case SETPASSENT: getb(fileno(stdin), &len, sizeof (int)); if (setpassent(len)) len = 1; else len = 0; write(fileno(stdout), &len, sizeof (int)); break; case ENDPWENT: endpwent(); break; default: abort("switch"); } } } getb(f, p, n) int f; register char *p; register int n; { register int i; while (n) { i = read(f, p, n); if (i <= 0) return; p += i; n -= i; } } void timeout() { longjmp(env, 1); } void checkppid() { if (getppid() == 1) exit(0); } do_pw(pw) struct passwd *pw; { int len; if (!pw) { len = 0; write(fileno(stdout), &len, sizeof (int)); return; } len = packpwtobuf(pw, junk); write(fileno(stdout), &len, sizeof (int)); write(fileno(stdout), pw, sizeof (*pw)); write(fileno(stdout), junk, len); return; } packpwtobuf(pw, buf) register struct passwd *pw; char *buf; { register char *cp = buf; register char *dp; dp = pw->pw_name; pw->pw_name = (char*) 0; while (*cp++ = *dp++) ; dp = pw->pw_passwd; pw->pw_passwd = (char*) (cp - buf); while (*cp++ = *dp++) ; dp = pw->pw_class; pw->pw_class = (char*) (cp - buf); while (*cp++ = *dp++) ; dp = pw->pw_gecos; pw->pw_gecos = (char*) (cp - buf); while (*cp++ = *dp++) ; dp = pw->pw_dir; pw->pw_dir = (char*) (cp - buf); while (*cp++ = *dp++) ; dp = pw->pw_shell; pw->pw_shell = (char*) (cp - buf); while (*cp++ = *dp++) ; return(cp - buf); }