?? oldprotocol.c++
字號:
/* $Id: OldProtocol.c++,v 1.14 2005/11/21 21:57:18 aidan Exp $ *//* * Copyright (c) 1995-1996 Sam Leffler * Copyright (c) 1995-1996 Silicon Graphics, Inc. * HylaFAX is a trademark of Silicon Graphics * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */#ifdef OLDPROTO_SUPPORT/* * ``Old Protocol'' Support. * * This optional module implements the old client-server * protocol using the new mechanisms (mostly). This * stuff is intended to be used for old clients that * cannot easily upgrade to use the new protocol (e.g. * the Mac- and PC-based clients). */#include "port.h"#include "Dispatcher.h"#include "OldProtocol.h"#include "Sys.h"#include "Socket.h"#include "config.h"#include <sys/file.h>#include <netdb.h>#include <ctype.h>extern "C" {#include <arpa/inet.h>#include <netinet/in_systm.h>#include <netinet/ip.h>}#define FAX_OSERVICE "fax" // old protocol service name#define FAX_ODEFPORT 4557 // old protocol default portOldProtocolSuperServer::OldProtocolSuperServer(const char* p, int bl) : SuperServer("Old", bl) , port(p){}OldProtocolSuperServer::~OldProtocolSuperServer() {}boolOldProtocolSuperServer::startServer(void){ int s = socket(AF_INET, SOCK_STREAM, 0); if (s >= 0) { struct sockaddr_in sin; memset(&sin, 0, sizeof (sin)); sin.sin_family = AF_INET; const char* cp = port; struct servent* sp = getservbyname(cp, FAX_PROTONAME); if (!sp) { if (isdigit(cp[0])) sin.sin_port = htons(atoi(cp)); else sin.sin_port = htons(FAX_ODEFPORT); } else sin.sin_port = sp->s_port; if (Socket::bind(s, &sin, sizeof (sin)) >= 0) { (void) listen(s, getBacklog()); Dispatcher::instance().link(s, Dispatcher::ReadMask, this); return (true); // success } Sys::close(s); logError("HylaFAX %s: bind (port %u): %m", getKind(), ntohs(sin.sin_port)); } else logError("HylaFAX %s: socket: %m", getKind()); return (false);}HylaFAXServer* OldProtocolSuperServer::newChild(void) { return new OldProtocolServer; }OldProtocolServer::OldProtocolServer(){ version = 0; alreadyChecked = false; codetab = NULL;}OldProtocolServer::~OldProtocolServer() {}voidOldProtocolServer::open(void){ setupNetwork(STDIN_FILENO); initServer(); if (TRACE(CONNECT)) logInfo("HylaFAX Old connection from %s [%s]", (const char*) remotehost, (const char*) remoteaddr); fxStr emsg; if (isShutdown(true)) { logInfo("HylaFAX Old connection refused (server shut down) from %s [%s]", (const char*) remotehost, (const char*) remoteaddr); dologout(-1); } if (!initClientFIFO(emsg)) { logInfo("HylaFAX Old connection refused (%s) from %s [%s]", (const char*) emsg, (const char*) remotehost, (const char*) remoteaddr); dologout(-1); } /* * We must chroot to the top of the spooling area to * mimic the new protocol; otherwise various pathname * assumptions will not be right. */ uid_t ouid = geteuid(); seteuid(0); if (chroot(".") < 0 || chdir("/") < 0) dologout(-1); seteuid(ouid); (void) umask(077); dirSetup(); // initialize directory handling /* * old protocol Jprintf format %Y historically gives localtime, * we'll force off USEGMT now that %Y is GMT/LOCAL aware, just like * SNNPServer. */ state &= ~S_USEGMT; doProtocol();}/* * Check host identity returned by gethostbyaddr to * weed out clients trying to spoof us (this is mostly * a sanity check; it's still trivial to spoof). * If the name returned by gethostbyaddr is in our domain, * look up the name and check that the peer's address * corresponds to the host name. */boolOldProtocolServer::checkHostIdentity(hostent*& hp){ if (!isLocalDomain(hp->h_name)) // not local, don't check return (true); fxStr name(hp->h_name); // must copy static value hp = Socket::gethostbyname(name); if (hp) { for (const char** cpp = (const char**) hp->h_addr_list; *cpp; cpp++) if (memcmp(*cpp, &peer_addr.sin_addr, hp->h_length) == 0) return (true); sendError("Client address %s is not listed for host name %s.", (const char*) remoteaddr, hp->h_name); } else sendError("No inverse address mapping for client host name %s.", (const char*) name); return (false);}voidOldProtocolServer::setupNetwork(int fd){ socklen_t addrlen; addrlen = sizeof (peer_addr); if (Socket::getpeername(fd, &peer_addr, &addrlen) < 0) { logError("getpeername: %m"); dologout(-1); } addrlen = sizeof (ctrl_addr); if (Socket::getsockname(fd, &ctrl_addr, &addrlen) < 0) { logError("getsockname: %m"); dologout(-1); }#if defined(IPTOS_LOWDELAY) { int tos = IPTOS_LOWDELAY; if (Socket::setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0) logWarning("setsockopt (IP_TOS): %m"); }#endif#if defined(SO_LINGER) && !defined(__linux__) { struct linger opt; opt.l_onoff = 1; opt.l_linger = 60; if (Socket::setsockopt(fd, SOL_SOCKET, SO_LINGER, &opt, sizeof (opt)) < 0) logWarning("setsockopt (SO_LINGER): %m"); }#endif#ifdef F_SETOWN if (fcntl(fd, F_SETOWN, getpid()) == -1) logError("fcntl (F_SETOWN): %m");#endif hostent* hp = gethostbyaddr((char*) &peer_addr.sin_addr, sizeof (struct in_addr), AF_INET); remoteaddr = inet_ntoa(peer_addr.sin_addr); if (remoteaddr == "0.0.0.0") remotehost = "localhost"; else if (hp) { if (checkHostIdentity(hp)) remotehost = hp->h_name; else remotehost = remoteaddr; } else { sendError("Can not map your network address (%s) to a hostname", (const char*) remoteaddr); remotehost = remoteaddr; }}// NB: there is no support for the old style data transferconst OldProtocolServer::protoCmd OldProtocolServer::cmds[] = {{ "begin", true, &OldProtocolServer::submitJob },{ "checkPerm", true, &OldProtocolServer::ackPermission },{ "tiff", true, &OldProtocolServer::getTIFFData },{ "postscript", true, &OldProtocolServer::getPostScriptData },{ "zpostscript", true, &OldProtocolServer::getZPostScriptData },{ "opaque", true, &OldProtocolServer::getOpaqueData },{ "zopaque", true, &OldProtocolServer::getZOpaqueData },{ "poll", true, &OldProtocolServer::newPollID },{ "userID", false, &OldProtocolServer::setUserID },{ "version", false, &OldProtocolServer::setProtoVersion },{ "serverStatus", false, &OldProtocolServer::sendServerStatus },{ "serverInfo", false, &OldProtocolServer::sendServerInfo },{ "allStatus", false, &OldProtocolServer::sendAllStatus },{ "userStatus", false, &OldProtocolServer::sendUserStatus },{ "jobStatus", false, &OldProtocolServer::sendJobStatus },{ "recvStatus", false, &OldProtocolServer::sendRecvStatus },{ "remove", true, &OldProtocolServer::removeJob },{ "removeGroup", true, &OldProtocolServer::removeJobGroup },{ "kill", true, &OldProtocolServer::killJob },{ "killGroup", true, &OldProtocolServer::killJobGroup },{ "alterTTS", true, &OldProtocolServer::alterJobTTS },{ "alterGroupTTS", true, &OldProtocolServer::alterJobGroupTTS },{ "alterKillTime", true, &OldProtocolServer::alterJobKillTime },{ "alterGroupKillTime", true, &OldProtocolServer::alterJobGroupKillTime },{ "alterMaxDials", true, &OldProtocolServer::alterJobMaxDials },{ "alterGroupMaxDials", true, &OldProtocolServer::alterJobGroupMaxDials },{ "alterNotify", true, &OldProtocolServer::alterJobNotification },{ "alterGroupNotify", true, &OldProtocolServer::alterJobGroupNotification },{ "alterModem", true, &OldProtocolServer::alterJobModem },{ "alterGroupModem", true, &OldProtocolServer::alterJobGroupModem },{ "alterPriority", true, &OldProtocolServer::alterJobPriority },{ "alterGroupPriority", true, &OldProtocolServer::alterJobGroupPriority },};#define NCMDS (sizeof (cmds) / sizeof (cmds[0]))#define isCmd(a) (strcasecmp(line,a) == 0)voidOldProtocolServer::doProtocol(void){ modem = MODEM_ANY; the_user = ""; char line[1024]; char* tag; for (;;) { getCommandLine(line, tag); if (isCmd(".")) break; if (isCmd("modem")) { // select outgoing device int l = strlen(_PATH_DEV); char* cp; /* * Convert modem name to identifier form by stripping * any leading device pathname prefix and by replacing * '/'s with '_'s for SVR4 where terminal devices are * in subdirectories. */ if (strncmp(tag, _PATH_DEV, l) == 0) tag += l; for (cp = tag; (cp = strchr(cp, '/')); *cp = '_') ; modem = tag; } else { u_int i; for (i = 0; i < NCMDS && !isCmd(cmds[i].cmd); i++) ; if (i == NCMDS) protocolBotch("unrecognized cmd \"%s\".", line); if (cmds[i].check) { if (!alreadyChecked) { if (!checkUser(the_user)) { logError("%s (%s): HylaFAX Old service refused", (const char*) remotehost, (const char*) remoteaddr); sendError( "Service refused; %s to use the fax server from %s (%s)." , "you do not have permission" , (const char*) remotehost , (const char*) remoteaddr ); dologout(-1); } alreadyChecked = true; } } (this->*cmds[i].cmdFunc)(tag); } } fflush(stdout); dologout(0);}voidOldProtocolServer::getCommandLine(char line[1024], char*& tag){ if (!fgets(line, 1024-1, stdin)) protocolBotch("unexpected EOF."); char* cp = strchr(line, '\0'); if (cp > line && cp[-1] == '\n') *--cp = '\0'; if (cp > line && cp[-1] == '\r') // for telnet users *--cp = '\0'; if (TRACE(PROTOCOL)) logDebug("line \"%s\"", line); if (strcmp(line, ".") && strcmp(line, "..")) { tag = strchr(line, ':'); if (!tag) protocolBotch("malformed line \"%s\".", line); *tag++ = '\0'; while (isspace(*tag)) tag++; }}extern int parseAtSyntax(const char*, const struct tm&, struct tm&, fxStr& emsg);u_longOldProtocolServer::cvtTime(const char* spec, const struct tm* ref, const char* what){ fxStr emsg; struct tm when; if (!parseAtSyntax(spec, *ref, when, emsg)) { sendAndLogError("Error parsing %s \"%s\": %s.", what, spec, (const char*) emsg); /*NOTREACHED*/ } return (u_long) mktime(&when);}voidOldProtocolServer::vsendClient(const char* tag, const char* fmt, va_list ap){ fxStr s = fxStr::format("%s:", tag) | fxStr::vformat(fmt, ap); fprintf(stdout, "%s\n", (const char*)s); if (TRACE(PROTOCOL)) { logDebug("%s", (const char*)s); }}voidOldProtocolServer::sendClient(const char* tag, const char* fmt, ...){ va_list ap; va_start(ap, fmt); vsendClient(tag, fmt, ap); va_end(ap);}voidOldProtocolServer::sendError(const char* fmt, ...){ va_list ap; va_start(ap, fmt); vsendClient("error", fmt, ap); va_end(ap);}voidOldProtocolServer::sendAndLogError(const char* fmt, ...){ va_list ap; va_start(ap, fmt); vsendClient("error", fmt, ap); va_end(ap); va_start(ap, fmt); vlogError(fmt, ap); va_end(ap); dologout(1);}voidOldProtocolServer::protocolBotch(const char* fmt, ...){ va_list ap; va_start(ap, fmt); fxStr buf(fxStr::format("Protocol botch, %s", fmt)); vsendClient("error", buf, ap); va_end(ap); va_start(ap, fmt); vlogError(buf, ap); va_end(ap); dologout(1);}/* * Miscellaneous protocol requests. *//* * Define client identity. */voidOldProtocolServer::setUserID(const char* tag){ the_user = tag; initDefaultJob(); if (TRACE(LOGIN)) logInfo("HylaFAX OLD LOGIN FROM %s [%s], %s" , (const char*) remotehost , (const char*) remoteaddr , (const char*) the_user );}/* * Add a poll request. */voidOldProtocolServer::newPollID(const char* tag){ reqs.append(FaxItem(FaxRequest::send_poll, 0, tag, ""));}/* * Set the required/expected protocol version. */voidOldProtocolServer::setProtoVersion(const char* tag){ version = atoi(tag); if (version > FAX_PROTOVERS) protocolBotch( "protocol version %u requested: only understand up to %u.", version, FAX_PROTOVERS);}/* * Send the client acknowledgement that * it has permission to submit jobs. */voidOldProtocolServer::ackPermission(const char*){ sendClient("permission", "%s", "granted");
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -