#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/tiuser.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mkdev.h>
#include <values.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <sys/poll.h>
#include <sys/stropts.h>
#include <utmpx.h>
#include <sac.h>
#include "lsparam.h"
#include "lsfiles.h"
#include "lserror.h"
#include "lsnlsmsg.h"
#include "lssmbmsg.h"
#include "lsdbf.h"
#include "listen.h"
FILE *Logfp;
#ifdef DEBUGMODE
FILE *Debugfp;
#endif
int Dbf_entries;
dbf_t *Dbfhead;
dbf_t *Newdbf;
char *New_cmd_lines;
char *Server_cmd_lines;
extern int t_errno;
int NLPS_proc = 1;
pid_t Pid;
char Lastmsg[BUFSIZ];
char *Netspec = NULL;
int Splflag = 0;
int Logmax = 0;
char *Mytag = NULL;
char msgbuf[BUFSIZ];
char Altbasedir[BUFSIZ];
char Basedir[BUFSIZ];
extern char *getenv();
static void nls_reply(int code, char *text);
static void nullfix(void);
int
main(int argc, char **argv)
{
extern int read_dbf();
char *provider;
provider = getenv("PMTAG");
sprintf(Altbasedir, "%s/%s/", ALTDIR, provider);
sprintf(Basedir, "%s/%s/", BASEDIR, provider);
sprintf(msgbuf, "%s/%s", Altbasedir, LOGNAME);
if (!(Logfp = fopen(msgbuf, "a+"))) {
(void)exit(1);
}
#ifdef DEBUGMODE
sprintf(msgbuf, "%s/%s", Altbasedir, PDEBUGNAME);
if (!(Debugfp = fopen(msgbuf, "a"))) {
logmessage("NLPS: Unable to open DEBUG file");
(void)exit(1);
}
#endif
if (t_sync(0) == -1) {
DEBUG((9,"t_sync failed, t_errno %d", t_errno));
logmessage("NLPS: Resynchronization of TLI failed");
(void)exit(1);
}
nlps_server();
return(0);
}
int
nlps_server()
{
int size;
char buf[RCVBUFSZ];
char **argv;
char *bp = buf;
dbf_t *dbp;
dbf_t *getdbfentry();
extern char **mkdbfargv();
Pid = getpid();
DEBUG((9,"in nlps_server (NLPS/SMB message), pid %ld", Pid));
if ((size = getrequest(bp)) <= 0) {
logmessage("NLPS: No/bad service request received");
return(-1);
}
if (size < 0) {
DEBUG((7,"nlps_server(): Error returned from getrequest()" ));
logmessage("NLPS: Error returned from getrequest()");
return(-1);
}
if ((!strncmp(bp,NLPSIDSTR,NLPSIDSZ)) &&
(*(bp + NLPSIDSZ) == NLPSSEPCHAR)) {
nls_service(bp, size);
(void)sleep(10);
} else if ( (*bp == (char)0xff) && (!strncmp(bp+1,SMBIDSTR,SMBIDSZ)) ) {
if (dbp = getdbfentry(DBF_SMB_CODE))
if (dbp->dbf_flags & DBF_OFF)
logmessage("NLPS: SMB message, server disabled in data base");
else {
argv = mkdbfargv(dbp);
smbservice(bp, size, argv);
}
else
logmessage("NLPS: SMB message, no data base entry");
} else {
logmessage("NLPS: Unknown service request (ignored)");
DEBUG((7,"msg size: %d; 1st four chars (hex) %x %x %x %x",
*bp, *(bp+1), *(bp+2), *(bp+3)));
}
return(-1);
}
int
getrequest(bp)
char *bp;
{
int size;
char *tmp = bp;
int flags;
extern void timeout();
short cnt;
void (*oldhanp)();
DEBUG((9,"in getrequest"));
oldhanp = signal(SIGALRM, timeout);
(void)alarm(ALARMTIME);
if ((size = l_rcv(bp, MINMSGSZ, &flags)) != MINMSGSZ) {
DEBUG((9, "getrequest: l_rcv returned %d", size));
tli_error(E_RCV_MSG, CONTINUE);
return(-1);
}
tmp += size;
if ((!strncmp(bp,NLPSIDSTR,NLPSIDSZ)) &&
(*(bp + NLPSIDSZ) == NLPSSEPCHAR)) {
do {
if (++size > RCVBUFSZ) {
logmessage("NLPS: recieve buffer not large enough");
return(-1);
}
if (t_rcv(0, tmp, sizeof(char), &flags) != sizeof(char)) {
tli_error(E_RCV_MSG, CONTINUE);
return(-1);
}
} while (*tmp++ != '\0');
} else if ( (*bp == (char)0xff) && (!strncmp(bp+1,SMBIDSTR,SMBIDSZ)) ) {
if (l_rcv(tmp, 28, &flags) != 28) {
tli_error(E_RCV_MSG, CONTINUE);
return(-1);
}
tmp += 28;
size += 28;
cnt = (int)*(tmp - 1) * 2 + 2;
if ((size += cnt) > RCVBUFSZ) {
logmessage("NLPS: recieve buffer not large enough");
return(-1);
}
if (l_rcv(tmp, cnt, &flags) != cnt) {
tli_error(E_RCV_MSG, CONTINUE);
return(-1);
}
tmp += cnt;
getword(tmp - 2, &cnt);
if ((size += cnt) > RCVBUFSZ) {
logmessage("NLPS: recieve buffer not large enough");
return(-1);
}
if (l_rcv(tmp, cnt, &flags) != cnt) {
tli_error(E_RCV_MSG, CONTINUE);
return(-1);
}
nullfix();
} else {
logmessage("NLPS: Unknown service request (ignored)");
DEBUG((7,"msg size: %d; 1st four chars (hex) %x %x %x %x",
*bp, *(bp+1), *(bp+2), *(bp+3)));
return(-1);
}
(void)alarm(0);
signal(SIGALRM, oldhanp);
DEBUG((7,"t_rcv returned %d, flags: %x",size,flags));
return(size);
}
static void
nullfix(void)
{
struct strpeek peek;
register struct strpeek *peekp;
char scratch[BUFSIZ];
char junk[2];
int flags;
int ret;
peekp = &peek;
peekp->flags = 0;
peekp->ctlbuf.maxlen = 1;
peekp->ctlbuf.buf = junk;
peekp->databuf.maxlen = 2;
peekp->databuf.buf = junk;
ret = ioctl(0, I_PEEK, &peek);
if (ret == -1) {
sprintf(scratch, "NLPS: nullfix(): unable to PEEK, errno is %d", errno);
DEBUG((9, "nullfix(): I_PEEK failed, errno is %d", errno));
logmessage(scratch);
}
else if (ret == 0) {
DEBUG((9, "nullfix(): no messages on stream to PEEK"));
}
else {
if (peekp->databuf.len == 2) {
DEBUG((9, "peeked <%x> <%x>", junk[0], junk[1]));
if ((junk[0] == 0) && (junk[1] == 0)) {
DEBUG((9, "pitching 2 nulls from first peek"));
l_rcv(junk, 2, &flags);
}
}
else if (peekp->databuf.len == 1) {
DEBUG((9, "peeked <%x>", junk[0]));
if (junk[0] == 0) {
DEBUG((9, "split nulls, pitching first"));
l_rcv(junk, 1, &flags);
peekp->databuf.maxlen = 1;
ret = ioctl(0, I_PEEK, &peek);
if (ret == -1) {
sprintf(scratch, "NLPS: nullfix(): unable to PEEK second time, errno is %d", errno);
DEBUG((9, "second peek failed, errno %d", errno));
logmessage(scratch);
}
else if (ret == 0) {
DEBUG((9, "no messages for 2nd peek"));
}
else {
if (peekp->databuf.len == 1) {
DEBUG((9, "2nd peek <%x>", junk[0]));
if (junk[0] == 0) {
DEBUG((9, "pitching 2nd single null"));
l_rcv(junk, 1, &flags);
}
else {
DEBUG((9, "2nd null not found"));
logmessage("NLPS: nullfix(): threw away a valid null byte");
}
}
}
}
}
}
}
void
timeout()
{
DEBUG((9, "TIMEOUT"));
error(E_RCV_TMO, EXIT | NOCORE);
}
static char *badversion =
"NLPS: Unknown version of an NLPS service request: %d:%d";
static char *disabledmsg =
"NLPS: Request for service code <%s> denied, service is disabled";
static char *nlsunknown =
"NLPS: Request for service code <%s> denied, unknown service code";
static int Nlsversion = -1;
int
nls_service(bp, size)
int size;
char *bp;
{
int low, high;
char svc_buf[64];
register char *svc_code_p = svc_buf;
char scratch[256];
register dbf_t *dbp;
dbf_t *getdbfentry();
extern char **mkdbfargv();
int passfd;
int i;
if (nls_chkmsg(bp, size, &low, &high, svc_code_p)) {
if ((low == 0) || (low == 2))
Nlsversion = low;
else {
sprintf(scratch, badversion, low, high);
logmessage(scratch);
error(E_BAD_VERSION, CONTINUE);
return(-1);
}
DEBUG((9,"nls_service: protocol version %d", Nlsversion));
if (dbp = getdbfentry(svc_code_p)) {
if (dbp->dbf_flags & DBF_OFF) {
sprintf(scratch, disabledmsg, svc_code_p);
logmessage(scratch);
nls_reply(NLSDISABLED, scratch);
}
else {
if (dbp->dbf_sflags & CFLAG) {
exec_cmd(dbp, (char **)0);
}
else {
sprintf(msgbuf,"NLPS (%s) passfd: %s",
dbp->dbf_svc_code,
dbp->dbf_cmd_line);
nls_reply(NLSSTART, msgbuf);
logmessage(msgbuf);
if ((passfd = open(dbp->dbf_cmd_line,
O_WRONLY)) < 0) {
sprintf(scratch,"NLPS open failed: %s", dbp->dbf_cmd_line);
logmessage(scratch);
}
DEBUG((9, "pushmod string: %s", dbp->dbf_modules));
if (pushmod(0, dbp->dbf_modules)) {
logmessage("NLPS: Can't push server's modules: exit");
(void)exit(2);
}
DEBUG((9, "Running doconfig on %s", dbp->dbf_svc_code));
sprintf(msgbuf,"%s/%s",Basedir,dbp->dbf_svc_code);
if ((i = doconfig(0, msgbuf, NOASSIGN)) != 0) {
DEBUG((9, "doconfig exited with code %d", i));
sprintf(scratch, "doconfig failed on line %d of script %s",
i, msgbuf);
logmessage(scratch);
(void)exit(2);
}
if (ioctl(passfd, I_SENDFD, 0) < 0) {
sprintf(scratch,"NLPS passfd failed: %s", dbp->dbf_cmd_line);
logmessage(scratch);
}
}
}
}
else {
sprintf(scratch, nlsunknown, svc_code_p);
logmessage(scratch);
nls_reply(NLSUNKNOWN, scratch);
}
exit(2);
} else
error(E_BAD_FORMAT, CONTINUE);
return(-1);
}
int
nls_chkmsg(bp, size, lowp, highp, svc_code_p)
char *bp, *svc_code_p;
int size, *lowp, *highp;
{
if ((*(bp + size - 1)) != (char)0)
return(0);
return(sscanf(bp, "%*4c:%3d:%3d:%s", lowp, highp, svc_code_p) == 3);
}
static char *srrpprot = "%d:%d:%s";
static void
nls_reply(int code, char *text)
{
char scratch[256];
if (Nlsversion >= 2) {
DEBUG((7, "nls_reply: sending response message"));
sprintf(scratch, srrpprot, Nlsversion, code, text);
t_snd(0, scratch, strlen(scratch)+1, 0);
}
}
static char homeenv[BUFSIZ];
#define NETFD 0
int
exec_cmd(dbf_t *dbp, char **o_argv)
{
char *path;
char **argvp;
extern char **environ;
dbf_t *getdbfentry();
extern char **mkdbfargv();
struct passwd *pwdp;
struct group *grpp;
dbf_t *wdbp = dbp;
int i;
if (o_argv) {
argvp = o_argv;
if ((wdbp = getdbfentry(DBF_SMB_CODE)) == NULL) {
logmessage("NLPS: SMB message, missing data base entry");
(void)exit(2);
}
}
else
argvp = mkdbfargv(dbp);
path = *argvp;
sprintf(msgbuf,"NLPS (%s) exec: %s",
(dbp)?dbp->dbf_svc_code:DBF_SMB_CODE, path);
nls_reply(NLSSTART, msgbuf);
logmessage(msgbuf);
if (wdbp->dbf_flags & DBF_UTMP) {
pid_t tmp;
struct stat sbuf;
char *prefix;
char device[20];
struct utmpx utline;
DEBUG((9, "Creating a utmpx entry for this service "));
if ((tmp = fork()) < 0) {
logmessage("NLPS: Can't fork to create utmpx entry");
exit(2);
}
if (tmp)
exit(0);
setpgrp();
if (fstat(0, &sbuf) < 0) {
logmessage("NLPS: Stat failed on fd 0: no line "
"field available for utmpx entry");
*device = '\0';
}
else {
prefix = getenv("MPREFIX");
if (minor(sbuf.st_rdev) < 100)
sprintf(device, "%.9s%02.02d", prefix, minor(sbuf.st_rdev));
else
sprintf(device, "%.8s%03.03d", prefix, minor(sbuf.st_rdev));
DEBUG((9, "Device: %s", device));
}
strncpy(utline.ut_user, wdbp->dbf_id,
sizeof (utline.ut_user) - 1);
sprintf(utline.ut_id, "ps%c%c", SC_WILDC, SC_WILDC);
strncpy(utline.ut_line, device, sizeof (utline.ut_line) - 1);
utline.ut_pid = getpid();
utline.ut_type = USER_PROCESS;
utline.ut_exit.e_termination = 0;
utline.ut_exit.e_exit = 0;
utline.ut_xtime = (time_t) time((time_t *)0);
makeutx(&utline);
}
DEBUG((9, "pushmod string: %s", wdbp->dbf_modules));
if (dbp && pushmod(NETFD, dbp->dbf_modules)) {
logmessage("NLPS: Can't push server's modules: exit");
exit(2);
}
DEBUG((9, "Running doconfig on %s", wdbp->dbf_svc_code));
if ((i = doconfig(NETFD, wdbp->dbf_svc_code, 0)) != 0) {
DEBUG((9, "doconfig exited with code %d", i));
sprintf(msgbuf, "doconfig failed on line %d of script %s",
i, wdbp->dbf_svc_code);
logmessage(msgbuf);
}
if (wdbp == NULL) {
logmessage("NLPS: No database entry");
exit(2);
}
if ((pwdp = getpwnam(wdbp->dbf_id)) == NULL) {
sprintf(msgbuf, "NLPS: Missing or bad passwd entry for <%s>",wdbp->dbf_id);
logmessage(msgbuf);
exit(2);
}
if (setgid(pwdp->pw_gid)) {
if ((grpp = getgrgid(pwdp->pw_gid)) == NULL) {
sprintf(msgbuf, "NLPS: No group entry for %ld", pwdp->pw_gid);
logmessage(msgbuf);
exit(2);
}
sprintf(msgbuf, "NLPS: Cannot set group id to %s", grpp->gr_name);
logmessage(msgbuf);
(void)exit(2);
}
if (setuid(pwdp->pw_uid)) {
sprintf(msgbuf, "NLPS: Cannot set user id to %s", wdbp->dbf_id);
logmessage(msgbuf);
(void)exit(2);
}
if (chdir(pwdp->pw_dir)) {
sprintf(msgbuf, "NLPS: Cannot chdir to %s", pwdp->pw_dir);
logmessage(msgbuf);
(void)exit(2);
}
DEBUG((9, "New uid %ld New gid %ld", getuid(), getgid()));
sprintf(homeenv, "HOME=%s", pwdp->pw_dir);
DEBUG((9,"HOME=%s", pwdp->pw_dir));
putenv(homeenv);
endpwent();
fclose(Logfp);
#ifdef DEBUGMODE
fclose(Debugfp);
#endif
execve(path, argvp, environ);
logmessage("NLPS server: could not exec service");
sys_error(E_SYS_ERROR, CONTINUE);
return(-1);
}
int
isdigits(p)
register char *p;
{
register int flag = 1;
if (!strlen(p))
return(0);
while (*p)
if (!isdigit(*p++))
flag = 0;
return(flag);
}
int
l_rcv(bufp, bytes, flagp)
char *bufp;
int bytes;
int *flagp;
{
register int n;
register int count = bytes;
register char *bp = bufp;
DEBUG((9, "in l_rcv"));
do {
*flagp = 0;
n = t_rcv(0, bp, count, flagp);
DEBUG((9, "l_rcv, after t_rcv call, n = %d",n));
if (n < 0) {
DEBUG((9, "l_rcv, t_errno is %d", t_errno));
#ifdef DEBUGMODE
if (t_errno == TLOOK) {
DEBUG((9, "l_rcv, t_look returns %d", t_look(0)));
}
#endif
return(n);
}
count -= n;
bp += n;
} while (count > 0);
return(bp - bufp);
}
static char Dbf_line_buf[DBFLINESZ];
static dbf_t Dbf_entry;
dbf_t *
getdbfentry(svc_code_p)
register char *svc_code_p;
{
FILE *dbfp;
char dbfname[BUFSIZ];
sprintf(dbfname, "%s/%s", Basedir, DBFNAME);
if ((dbfp = fopen(dbfname, "r")) == NULL) {
DEBUG((9, "open of database file %s failed", DBFNAME));
logmessage("NLPS: Unable to open database file");
return((dbf_t *)NULL);
}
DEBUG((9, "database file opened, looking for %s", svc_code_p));
while (rd_dbf_line(dbfp, Dbf_line_buf, &Dbf_entry.dbf_svc_code,
&Dbf_entry.dbf_flags, &Dbf_entry.dbf_id, &Dbf_entry.dbf_res1,
&Dbf_entry.dbf_res2, &Dbf_entry.dbf_res3,&Dbf_entry.dbf_prv_adr,
&Dbf_entry.dbf_prognum, &Dbf_entry.dbf_version,
&Dbf_entry.dbf_modules, &Dbf_entry.dbf_sflags,
&Dbf_entry.dbf_cmd_line) > 0) {
if (!strcmp(Dbf_entry.dbf_svc_code, svc_code_p)) {
fclose(dbfp);
return(&Dbf_entry);
}
}
DEBUG((9, "No svc code match"));
fclose(dbfp);
return((dbf_t *)0);
}