You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/ktalkd/ktalkd/process.cpp

286 lines
10 KiB

/*
* Copyright (c) 1983 Regents of the University of California,
* (c) 1998 David Faure.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* (BSD License, from kdelibs/doc/common/bsd-license.html)
*/
/*
* process.cpp handles the requests, which can be of three types:
* ANNOUNCE - announce to a user that a talk is wanted
* LEAVE_INVITE - insert the request into the table
* LOOK_UP - look up to see if a request is waiting in
* in the table for the local user
* DELETE - delete invitation
*/
#include "includ.h"
#include <sys/param.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include <netdb.h>
#include <syslog.h>
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include "process.h"
#include "proto.h"
#include "announce.h"
#include "find_user.h"
#include "table.h"
#include "readconf.h"
#include "defs.h"
#include "machines/forwmach.h"
extern KTalkdTable * ktable;
int prepare_response(NEW_CTL_MSG *mp, NEW_CTL_RESPONSE *rp)
{
rp->type = mp->type;
rp->id_num = htonl(0);
rp->vers = mp->vers;
if ((mp->vers != 0) && (mp->vers != TALK_VERSION)) {
syslog(LOG_WARNING, "Bad protocol version %d", mp->vers);
rp->answer = BADVERSION;
return 0;
}
mp->id_num = ntohl(mp->id_num);
#if 0 // not in the original talkd anymore?
mp->addr.ta_family = ntohs(mp->addr.ta_family);
mp->ctl_addr.ta_family = ntohs(mp->ctl_addr.ta_family);
if (mp->ctl_addr.ta_family != AF_INET) {
syslog(LOG_WARNING, "Bad address, family %d",
mp->ctl_addr.ta_family);
rp->answer = BADCTLADDR;
return 0;
}
#endif
mp->pid = ntohl(mp->pid);
return 1; /* Ok */
}
int process_request(NEW_CTL_MSG *mp, NEW_CTL_RESPONSE *rp, const char* theirhost)
{
NEW_CTL_MSG *ptr;
int ret;
int usercfg = 0; /* set if a user config file exists */
print_request("process_request", mp);
if (!prepare_response(mp, rp))
return PROC_REQ_ERR;
/* Ensure null-termination */
mp->l_name[sizeof(mp->l_name)-1] = 0;
mp->r_name[sizeof(mp->r_name)-1] = 0;
mp->r_tty[sizeof(mp->r_tty)-1] = 0;
ret = PROC_REQ_OK;
switch (mp->type) {
case ANNOUNCE:
/* Open user config file. */
usercfg = init_user_config(mp->r_name);
ret = do_announce(mp, rp, theirhost, usercfg);
if (usercfg) end_user_config();
/* Store in table if normal announce or answmach replacing it.
Not if re-announce, nor if error, nor for forwarding machine */
if ((ret == PROC_REQ_OK) || (ret == PROC_REQ_ANSWMACH_NOT_LOGGED)
|| (ret == PROC_REQ_ANSWMACH_NOT_HERE))
ktable->insert_table(mp, rp, 0L);
case LEAVE_INVITE:
ptr = ktable->find_request(mp);
if (ptr != (NEW_CTL_MSG *)0) {
rp->id_num = htonl(ptr->id_num);
rp->answer = SUCCESS;
} else
ktable->insert_table(mp, rp, 0L);
break;
case LOOK_UP:
ptr = ktable->find_match(mp);
if (ptr != (NEW_CTL_MSG *)0) {
rp->id_num = htonl(ptr->id_num);
rp->addr = ptr->addr;
rp->addr.ta_family = htons(ptr->addr.ta_family);
rp->answer = SUCCESS;
} else {
if (ForwMachine::forwMachProcessLookup(ktable->getTable(), mp)) {
ret = PROC_REQ_FORWMACH; // Don't send any response, forwmach will do it
} else
rp->answer = NOT_HERE;
}
break;
case DELETE:
rp->answer = ktable->delete_invite(mp->id_num);
break;
default:
rp->answer = UNKNOWN_REQUEST;
break;
}
if (ret != PROC_REQ_FORWMACH)
print_response("=> response", rp);
if (mp->vers == 0) { // it's kotalkd talking to us.
// Let's prepare an OTALK response, shifting the first 2 fields
rp->vers /*type in otalk*/ = rp->type;
rp->type /*answer in otalk*/ = rp->answer;
}
return ret;
}
int do_announce(NEW_CTL_MSG *mp, NEW_CTL_RESPONSE *rp, const char* theirhost, int usercfg)
{
NEW_CTL_MSG *ptr;
int result;
char disp[DISPLAYS_LIST_MAX];
char forward[S_CFGLINE], forwardMethod[4];
char * callee;
ForwMachine * fwm;
/* Check if already in the table */
ptr = ktable->find_request(mp);
/* TODO use Voodo #1 from current process.c for byte-swapping stuff */
if ((ptr != NULL) && (
(mp->id_num <= ptr->id_num) || (mp->id_num == (uint32_t)~0x0L))) {
/* a duplicated request, so ignore it */
ktalk_debug("dupannounce %d", mp->id_num);
rp->id_num = htonl(ptr->id_num);
rp->answer = SUCCESS;
return PROC_REQ_ERR;
} else {
if (ptr == (NEW_CTL_MSG *) 0) { /* Not already in the table */
/* see if a forward has been set up */
if ( (usercfg)
&& (read_user_config("Forward", forward, S_CFGLINE))
&& (read_user_config("ForwardMethod", forwardMethod, 4 )) )
{
fwm = new ForwMachine(mp, forward, forwardMethod, mp->id_num);
/* Store in table, because :
(Any method) : this allows to detect dupannounces.
(FWR & FWT) : we'll receive the LOOK_UP */
ktable->insert_table(mp, 0L, fwm);
fwm->start(mp->id_num);
return PROC_REQ_FORWMACH;
}
}
/* see if the user is logged */
char tty[ UT_LINESIZE ]; // mp->r_tty may be smaller then UT_LINESIZE
*tty = '\0';
result = find_user(mp->r_name, tty, disp);
strlcpy( mp->r_tty, tty, sizeof( mp->r_tty ));
ktalk_debug("find_user : result = %d",result);
if (result != SUCCESS) {
ktalk_debug("Couldn t find user ...");
if (result == NOT_HERE)
{ /* Not here ? -> Start answering machine ! */
if (getpwnam(mp->r_name)) /* Does the user exist ? */
{ /* Yes ! -> SUCCESS. */
ktalk_debug("Not logged.");
rp->answer = SUCCESS;
endpwent();
return PROC_REQ_ANSWMACH_NOT_LOGGED; /* answer machine. */
} else
{ /* Non-existent user ... */
endpwent();
/* output an error into the logs */
syslog(LOG_ERR,"User unknown : %s.",mp->r_name);
syslog(LOG_ERR,"The caller is : %s.",mp->l_name);
switch (Options.NEU_behaviour) {
case 2: /* Paranoid setting. Do nothing. */
ktalk_debug("Paranoid setting. Do nothing.");
rp->answer = NOT_HERE;
return PROC_REQ_ERR;
case 0: /* Launch answering machine. */
ktalk_debug("Not here.");
rp->answer = SUCCESS;
return PROC_REQ_ANSWMACH_NOT_HERE;
case 1: /* NEU_user will take the talk. */
ktalk_debug("Not here. I ll take the talk.");
fwm = new ForwMachine(mp, Options.NEU_user,
Options.NEU_forwardmethod, mp->id_num);
/* store in table, because we'll receive the LOOK_UP */
ktable->insert_table(mp, 0L, fwm);
fwm->start(mp->id_num);
return PROC_REQ_FORWMACH;
} /* switch */
} /* getpwnam */
} /* result */
else {
ktalk_debug("not SUCCESS, nor NOT_HERE");
rp->answer = result; /* not SUCCESS, nor NOT_HERE*/
return PROC_REQ_ERR;
}
}
/* Check if there is a forwarding machine on this machine,
matching answerer = r_name and caller = l_name
Then set callee to the initial callee, to display in ktalkdlg */
callee = ForwMachine::forwMachFindMatch(ktable->getTable(), mp);
if (ptr == (NEW_CTL_MSG *) 0) { /* Not already in the table => announce */
rp->answer = announce(mp, theirhost, disp, usercfg, callee);
if (rp->answer == PERMISSION_DENIED) return PROC_REQ_ERR;
ktalk_debug("Announce done.");
return PROC_REQ_OK;
} else {
/* This is an explicit re-announce, so update the id_num
* field to avoid duplicates and re-announce the talk. */
int new_id_num = ktable->new_id();
if (Options.debug_mode)
syslog(LOG_DEBUG, "reannounce : updating id %d to id %d",
ptr->id_num, new_id_num);
ptr->id_num = new_id_num; /* update in the table */
rp->id_num = htonl(ptr->id_num);
rp->answer = announce(mp, theirhost, disp, usercfg, callee);
return PROC_REQ_ANSWMACH;
}
}
}