/******************************************************************************
* This file is part of a software distribution, which is furnished under the *
* terms of a license. Use of this software by any means is subject to this *
* license and signifies the acceptance of the licensing terms stated *
* therein. Please see the file LICENSE in the top-level directory of this *
* software distribution for detailed copyright disclaimers and licensing *
* terms. *
******************************************************************************
* Copryight (c) by Andreas S. Wetzel - All rights reserved. *
******************************************************************************/
/* $Id: commands.c,v 1.5 2002/06/23 23:29:37 mickey Exp $ */
#include <vchat.h>
#include <proto_common.h>
#include <netdb.h>
#if HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#include <ctype.h>
#include <arpa/inet.h>
/*** Externals ***/
extern VCONN sconn;
extern VP vp;
extern ED *ed;
extern int uchannel;
extern int input_line(char *prompt, size_t maxlen, u_short flags);
extern void vquit(char *fmt, ...);
/*** Code ***/
void aclcmd(char *dat)
{
VACL acl;
char *cmdargv[4];
char **aptr;
char *mask;
char *s;
char cmd;
char act;
int i;
int nextarg = 0;
int cmdargc = 0;
int mask_bits;
u_short rule;
struct in_addr address;
struct in_addr netmask;
u_int32_t ttl;
/*
* If no arguments are given, request ACL command.
*/
if(dat != NULL)
{
while(isspace((int)*dat))
++dat;
}
if(dat == NULL || *dat == '\0')
{
char prompt[64];
sprintf(prompt, "%sACL command%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 64, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
dat = ed->buffer;
}
/*
* Split input line into argument vector
*/
#if HAVE_STRSEP
for(aptr = cmdargv; (*aptr = (char *) strsep(&dat, " \t")) != NULL && cmdargc < 5;)
{
if(**aptr != '\0')
{
++aptr;
++cmdargc;
}
}
#else
aptr = cmdargv;
*aptr = (char *)strtok(dat, " \t");
while(*aptr != NULL && cmdargc < 4)
{
++aptr;
++cmdargc;
*aptr = (char *)strtok(NULL, " \t");
}
#endif
/*
* No arguments - no action
*/
if(cmdargc <= 0)
{
cprintf(chat, "* No ACL command specified - type '.A ?' for a list of ACL commands");
return;
}
/*
* Process the arguments contained in the command vector.
* The first argument is either one of the commands "add",
* "delete" or "flush". Otherwise the "add" command is
* assumed, and the first argument to be a valid rule number.
*/
str_lower(cmdargv[0]);
if(!strcmp(cmdargv[0], "add"))
{
cmd = 'a';
nextarg = 1;
}
else if(!strcmp(cmdargv[0], "delete"))
{
cmd = 'd';
nextarg = 1;
}
else if(!strcmp(cmdargv[0], "flush"))
{
cmd = 'f';
nextarg = 1;
}
else if(!strcmp(cmdargv[0], "list"))
{
cmd = 'l';
nextarg = 1;
}
else if(!strcmp(cmdargv[0], "help") || !strcmp(cmdargv[0], "?"))
{
/*
* Display ACL help
*/
cprintf(chat, "\n* %sV%sChat%s -- Interactive TCP/IP conference system -- %sACL COMMAND HELP%s:",
S_FG_MAG, S_FG_YEL, S_OFF, S_FG_CYN, S_OFF);
cprintf(chat, "*\n* ACL commands modify the contents of the servers ACL database and");
cprintf(chat, "* may be used by users with the %sACL%s permission only.", S_BOLD, S_OFF);
cprintf(chat, "*\n* %sAvailable ACL commands are:%s\n*",
S_UL, S_OFF);
cprintf(chat, "* %s.A%s [add] <rule> <action> <address> [ttl] - add an ACL rule to the database", S_FG_GRN, S_OFF);
cprintf(chat, "* %s.A%s delete <rule> - delete ACL rule from database", S_FG_GRN, S_OFF);
cprintf(chat, "* %s.A%s flush - flush all rules in ACL database", S_FG_GRN, S_OFF);
cprintf(chat, "* %s.A%s list - list all rules in ACL database\n*", S_FG_GRN, S_OFF);
cprintf(chat, "* %sWhere:%s\n*", S_UL, S_OFF);
cprintf(chat, "* %s<rule>%s - a rule number in the range 0..65534", S_BOLD, S_OFF);
cprintf(chat, "* %s<action>%s - action to be taken by this rule (accept|reject)", S_BOLD, S_OFF);
cprintf(chat, "* %s<address>%s - the internet name or address of a host or subnet", S_BOLD, S_OFF);
cprintf(chat, "* subnets are specified with a '/' followed by the netmask");
cprintf(chat, "* or number of netmask bits appended to the address i.e.:\n*");
cprintf(chat, "* %s127.0.0.0/8%s", S_BOLD, S_OFF);
cprintf(chat, "* %s10.0.0.0/255.0.0.0%s\n*", S_BOLD, S_OFF);
cprintf(chat, "* %s[ttl]%s - optional time to live specification in seconds", S_BOLD, S_OFF);
return;
}
else
{
cmd = 'a';
nextarg = 0;
i = strtol(cmdargv[nextarg], &s, 0);
if(*cmdargv[nextarg] == '\0' || *s != '\0')
{
cprintf(chat, "* Unknown ACL command '%s' - type '.A ?' for a list of ACL commands", cmdargv[nextarg]);
return;
}
}
/*
* Check for correct number of arguments
*/
switch(cmd)
{
case 'a': if((cmdargc - nextarg) != 3 && (cmdargc - nextarg) != 4)
{
cprintf(chat, "* The ACL 'add' command expects 3 or 4 arguments, not %d", (cmdargc - nextarg));
return;
}
break;
case 'd': if((cmdargc - nextarg) != 1)
{
cprintf(chat, "* The ACL 'delete' command expects 1 argument, not %d", (cmdargc - nextarg));
return;
}
break;
case 'f': if((cmdargc - nextarg) != 0)
{
cprintf(chat, "* The ACL 'flush' command expects no arguments");
return;
}
/*
* SEND ACL FLUSH COMMAND!
*/
snd_serv(CMD_ACL_FLUSH, NULL, 0);
return;
case 'l': if((cmdargc - nextarg) != 0)
{
cprintf(chat, "* The ACL 'list' command expects no arguments");
return;
}
/*
* SEND ACL LIST COMMAND!
*/
snd_serv(CMD_ACL_LIST, NULL, 0);
return;
}
/*
* For the "add" and delete commands, parse the rule number
*/
i = strtol(cmdargv[nextarg], &s, 0);
if(*cmdargv[nextarg] == '\0' || *s != '\0')
{
cprintf(chat, "* Numerical value expected in field %d of ACL command", nextarg + 1);
return;
}
if(i < 0 || i > 65534)
{
cprintf(chat, "* Rule number out of range - use a value between 0 and 65534");
return;
}
rule = (u_short) i;
++nextarg;
/*
* Delete command needs no further args, so do it now.
*/
if(cmd == 'd')
{
u_short rlnum = htons(rule);
/*
* SEND ACL DELETE COMMAND
*/
snd_serv(CMD_ACL_DELETE, (u_char *)&rlnum, sizeof(u_short));
return;
}
/*
* Next argument for an "add" command is the action to be taken
*/
str_lower(cmdargv[nextarg]);
if(!strcmp(cmdargv[nextarg], "allow")
|| !strcmp(cmdargv[nextarg], "pass")
|| !strcmp(cmdargv[nextarg], "accept")
|| !strcmp(cmdargv[nextarg], "grant"))
{
act = 'a'; /*** ACCEPT ***/
}
else if(!strcmp(cmdargv[nextarg], "deny")
|| !strcmp(cmdargv[nextarg], "reject")
|| !strcmp(cmdargv[nextarg], "refuse")
|| !strcmp(cmdargv[nextarg], "intercept")
|| !strcmp(cmdargv[nextarg], "void"))
{
act = 'r'; /*** REJECT ***/
}
else
{
cprintf(chat, "* Syntax error - '%s' unexpected", cmdargv[nextarg]);
return;
}
++nextarg;
/*
* The next argument to the "add" command is an address/netmask pair
* or the word "any" or "all"
*/
str_lower(cmdargv[nextarg]);
if(!strcmp(cmdargv[nextarg], "any") || !strcmp(cmdargv[nextarg], "all"))
{
address.s_addr = INADDR_ANY;
netmask.s_addr = INADDR_ANY;
mask_bits = 0;
}
else if((mask = (char *)strchr(cmdargv[nextarg], '/')) != NULL)
{
*mask++ = '\0';
address.s_addr = inet_addr(cmdargv[nextarg]);
if(address.s_addr == INADDR_NONE)
{
/*
* MALFORMED ADDRESS
* See if DNS lookup succeeds
*/
struct hostent *ht;
if((ht = gethostbyname(cmdargv[nextarg])) == NULL)
{
cprintf(chat, "* No address associated with '%s'", cmdargv[nextarg]);
return;
}
BCOPY(ht->h_addr, &address, sizeof(address));
}
if((s = (char *)strchr(mask, '.')) != NULL)
{
netmask.s_addr = inet_addr(mask);
mask_bits = netmask_bits(netmask);
}
else
{
mask_bits = atoi(mask);
netmask_create(mask_bits, &netmask);
}
}
else
{
if((address.s_addr = inet_addr(cmdargv[nextarg])) == INADDR_NONE)
{
/*
* MALFORMED ADDRESS
* See if DNS lookup succeeds on the argument
*/
struct hostent *ht;
if((ht = gethostbyname(cmdargv[nextarg])) == NULL)
{
cprintf(chat, "* No address associated with '%s'", cmdargv[nextarg]);
return;
}
BCOPY(ht->h_addr, &address, sizeof(address));
}
netmask.s_addr = htonl(0xffffffff);
mask_bits = netmask_bits(netmask);
}
++nextarg;
/*
* Look for optional TTL argument to ADD command.
*/
ttl = (cmdargc > nextarg) ? strtol(cmdargv[nextarg], NULL, 0) : 0;
/*
* SEND ACL ADD COMMAND
*/
acl.address = address;
acl.netmask = netmask;
acl.action = htons((act == 'a') ? ACL_ACT_ACCEPT : ACL_ACT_REJECT);
acl.rule = htons(rule);
acl.ttl = htonl(ttl);
snd_serv(CMD_ACL_ADD, (u_char *)&acl, sizeof(VACL));
}
void action(char *dat)
{
char *arg = dat;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
sprintf(prompt, "%sAction message%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
snd_serv(CMD_ACTION, arg, strlen(arg));
}
void addnick(char *dat)
{
u_char snd_buf[VPNICKSIZE+VPPASSWDSIZE+2];
u_char nick_buf[VPNICKSIZE+1];
u_char pwd_buf[VPPASSWDSIZE+1];
u_char prompt[64];
size_t sndlen;
/*
* Request nickname if not already given on the commandline
*/
BZERO(nick_buf, VPNICKSIZE+1);
if(dat == NULL || *dat == '\0')
{
sprintf(prompt, "%sAdd nickname%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, VPNICKSIZE, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
strncpy(nick_buf, ed->buffer, VPNICKSIZE);
}
else
{
if(strlen(dat) > VPNICKSIZE)
{
cprintf(chat, "* Please choose a nickname with at most %d characters",
VPNICKSIZE);
return;
}
strncpy(nick_buf, dat, VPNICKSIZE);
}
/*
* Request password for new account
*/
BZERO(pwd_buf, VPPASSWDSIZE+1);
sprintf(prompt, "%sPassword%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, VPPASSWDSIZE, (ED_RST_CTX | ED_NO_ECHO)))
{
cprintf(chat, "* Command aborted");
clear_input();
return;
}
clear_input();
strncpy(pwd_buf, ed->buffer, VPPASSWDSIZE);
sprintf(prompt, "%sVerification%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
input_line(prompt, VPPASSWDSIZE, (ED_RST_CTX | ED_NO_ECHO));
clear_input();
if(strncmp(pwd_buf, ed->buffer, VPPASSWDSIZE))
{
cprintf(chat, "* Verification failed");
return;
}
clear_ed(ed);
/*
* Send the ADDNICK command to the server
*/
sprintf(snd_buf, "%s %s", nick_buf, pwd_buf);
sndlen = strlen(snd_buf);
BZERO(pwd_buf, VPPASSWDSIZE+1);
snd_serv(CMD_ADDNICK, snd_buf, sndlen);
BZERO(snd_buf, (VPNICKSIZE+VPPASSWDSIZE+2));
}
void broadcast(char *dat)
{
char *arg = dat;
if(dat == NULL || *dat == '\0')
{
char prompt[64];
sprintf(prompt, "%sBroadcast message%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
snd_serv(CMD_BROADCAST, arg, strlen(arg));
}
void chchan(char *chan)
{
char *arg = chan;
signed long channel;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
sprintf(prompt, "%sEnter channel%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 16, ED_RST_CTX))
{
cprintf(chat, "* Command aborted\n");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
channel = htonl(strtol(arg, NULL, 0));
snd_serv(CMD_CHCHAN, (char *)&channel, sizeof(long));
}
void clientopts(char *dat)
{
GSOPT opt;
char *giveargv[32];
char *takeargv[32];
u_char giveargc = 0;
u_char takeargc = 0;
u_int32_t givemask = 0;
u_int32_t takemask = 0;
u_int32_t md;
char *arg = dat;
register int i;
#if HAVE_SYS_UIO_H
struct iovec iov[4];
VMSG vmsg;
#else
u_char *sndbuf;
VMSG *vmsg;
#endif
/*
* Parse client option operators with leading '-' or '+' character
* into takeargv[] and giveargv[] respectively.
*/
while(*arg != '\0')
{
if(*arg == '+')
{
*arg++ = '\0';
if(*arg == '\0' || *arg == ' ' || *arg == '\t')
{
cprintf(chat, "* Missing option name for '+' operator");
return;
}
giveargv[giveargc++] = arg;
while(*arg != '+' && *arg != '-' && *arg != ' '
&& *arg != '\t' && *arg != '\0')
{
++arg;
}
}
else if(*arg == '-')
{
*arg++ = '\0';
if(*arg == '\0' || *arg == ' ' || *arg == '\t')
{
cprintf(chat, "* Missing option name for '-' operator");
return;
}
takeargv[takeargc++] = arg;
while(*arg != '+' && *arg != '-' && *arg != ' '
&& *arg != '\t' && *arg != '\0')
{
++arg;
}
}
else if(*arg == ' ' || *arg == '\t')
{
*arg++ = '\0';
}
else
{
cprintf(chat, "* Invalid statement '%s' encountered",
arg);
return;
}
}
/*
* Create givemask and takemask corresponding to the
* option names specified in giveargv[] and takeargv[]
*/
for(i = 0; i < giveargc; i++)
{
if(clopt_mask(giveargv[i], &md) == -1)
{
cprintf(chat, "* Unknown client option name '%s'", giveargv[i]);
return;
}
givemask |= md;
}
for(i = 0; i < takeargc; i++)
{
if(clopt_mask(takeargv[i], &md) == -1)
{
cprintf(chat, "* Unknown client option name '%s'", takeargv[i]);
return;
}
takemask |= md;
}
/*
* Check for options that will compensate each other
*/
md = (givemask ^ takemask);
givemask &= md;
takemask &= md;
/*
* Fill in GSOPT structure
*/
opt.givemask = htonl(givemask);
opt.takemask = htonl(takemask);
opt.control = 0;
#if HAVE_SYS_UIO_H
/*
* Prepare scatter/gather array
*/
vmsg.cmd = htonl(CMD_CLOPT);
vmsg.len = htonl(sizeof(GSOPT));
iov[0].iov_base = (char *)&vmsg;
iov[0].iov_len = sizeof(vmsg);
iov[1].iov_base = (char *)&opt;
iov[1].iov_len = sizeof(GSOPT);
/*
* Send command
*/
writev(sconn.fd, (struct iovec *)&iov, 2);
#else
/*
* Prepare send buffer
*/
md = (sizeof(VMSG) + sizeof(GSOPT));
if((sndbuf = (u_char *)malloc(md + 1)) == NULL)
{
cprintf(chat, "* Memory allocation error (%s%s%s)",
S_FG_RED, strerror(errno), S_OFF);
return;
}
vmsg = (VMSG *)sndbuf;
vmsg->cmd = htonl(CMD_CLOPT);
vmsg->len = htonl(md - sizeof(VMSG));
BCOPY(&opt, (u_char *)(sndbuf + sizeof(VMSG)), sizeof(GSOPT));
/*
* Send command
*/
write(sconn.fd, sndbuf, md);
free(sndbuf);
#endif
}
void fixchan(char *dat)
{
char *tp;
if(dat == NULL || *dat == '\0')
{
cprintf(chat, "* Command aborted");
return;
}
if((tp = (char *)strchr(dat, ':')) != NULL)
{
size_t len;
/*
* Create a fixed channel
*/
*tp++ = '\0';
if((len = strlen(tp)) <= 0)
{
cprintf(chat, "* No topic specified");
}
else
{
u_char sndbuf[64];
int32_t *lp = (int32_t *)&sndbuf;
u_char *topic = &sndbuf[sizeof(signed long)];
BZERO(sndbuf, sizeof(sndbuf));
*lp = htonl(strtol(dat, NULL, 0));
strncpy(topic, tp, VPTOPICSIZE);
snd_serv(CMD_FIXCHAN, sndbuf, len + sizeof(int32_t));
}
}
else
{
int32_t chan = htonl(strtol(dat, NULL, 0));
snd_serv(CMD_FIXCHAN, (void *)&chan, sizeof(chan));
}
}
void lastlog(char *dat)
{
char *arg;
char *nicklist;
u_int32_t num;
u_int32_t *sndnum;
char *sndlst;
size_t size;
if(dat == NULL || *dat == '\0')
{
char prompt[64];
sprintf(prompt, "%sList how many entries%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
num = htonl(strtol(ed->buffer, NULL, 0));
sprintf(prompt, "%sShow which nickname(s) [blank=all]%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
nicklist = "";
else
nicklist = ed->buffer;
}
else if((arg = (char *)strchr(dat, ' ')) != NULL)
{
*arg++ = '\0';
num = htonl(strtoul(dat, NULL, 0));
nicklist = arg;
}
else
{
char prompt[64];
num = htonl(strtoul(dat, NULL, 0));
sprintf(prompt, "%sShow which nickname(s) [blank=all]%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
nicklist = "";
else
nicklist = ed->buffer;
}
/*
* Construct request
*/
size = (sizeof(num) + strlen(nicklist) + 1);
if((arg = calloc(1, size)) == NULL)
{
cprintf(chat, "* Memory allocation error - cannot send message");
return;
}
sndnum = (u_int32_t *)arg;
sndlst = (char *)(arg + sizeof(num));
*sndnum = num;
strcpy(sndlst, nicklist);
/*
* Send request
*/
snd_serv(CMD_LASTLOG, arg, size);
free(arg);
}
void modify_permissions(char *dat)
{
char *giveargv[32];
char *takeargv[32];
u_char giveargc = 0;
u_char takeargc = 0;
u_int32_t givemask = 0;
u_int32_t takemask = 0;
u_int32_t md;
u_char permset = 'a';
char *arg = dat;
char *nicklist;
register int i;
#if HAVE_SYS_UIO_H
struct iovec iov[4];
VMSG vmsg;
#else
u_char *sndbuf;
VMSG *vmsg;
#endif
/*
* See which permission set is to be modified (access|modify)
*/
if(dat == NULL || *dat == '\0')
{
char prompt[64];
sprintf(prompt, "%sModify command (? for help)%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
switch(tolower(*arg))
{
case '\0': cprintf(chat, "* Permission set specifier missing");
return;
case 'a': permset = 'a';
break;
case 'm': permset = 'm';
break;
case 'h':
case '?': /*** DISPLAY HELP ***/
cprintf(chat, "\n* %sV%sChat%s -- Interactive TCP/IP conference system -- %sMODIFY COMMAND HELP%s:",
S_FG_MAG, S_FG_YEL, S_OFF, S_FG_CYN, S_OFF);
cprintf(chat, "*\n* The %s.M%s command modifies the %saccess%s or %smodification%s permissions of",
S_FG_GRN, S_OFF, S_BOLD, S_OFF,
S_BOLD, S_OFF);
cprintf(chat, "* registered users and may be used with the %sCHACC%s or %sCHMOD%s access",
S_BOLD, S_OFF, S_BOLD, S_OFF);
cprintf(chat, "* permission only. Permissions may be modified only in accordance");
cprintf(chat, "* to your own %smodification%s permissions.",
S_BOLD, S_OFF);
cprintf(chat, "*\n* %sSynopsis:%s", S_UL, S_OFF);
cprintf(chat, "*\n* %s.M%s <a|m|?> <-/+perm> ... <nick> ...",
S_FG_GRN, S_OFF);
cprintf(chat, "*\n* %sWhere:%s", S_UL, S_OFF);
cprintf(chat, "*\n* <a|m|?> - Specifies if you want to modify %sa%sccess or %sm%sodify permissions",
S_BOLD, S_OFF, S_BOLD, S_OFF);
cprintf(chat, "* <-/+perm> - The permissions you want to deny or grant which can be any of:");
cprintf(chat, "* ADD, DELETE, CHACC, CHMOD, KILL, BCAST or ACL");
cprintf(chat, "* <nick> - One or more nickname(s) whose permissions will be modified");
return;
default: cprintf(chat, "* Invalid permission set specifier '%c'", *arg);
return;
}
if(*(++arg) == ' ')
*arg++ = '\0';
/*
* Parse mode change operators with leading '-' or '+' character
* into takeargv[] and giveargv[] respectively. Find the start of
* the specified nicknamelist (if any)
*/
nicklist = arg;
while(*arg != '\0')
{
if(*arg == '+')
{
nicklist = NULL;
*arg++ = '\0';
if(*arg == '\0' || *arg == ' ' || *arg == '\t')
{
cprintf(chat, "* Missing permission name for '+' operator");
return;
}
giveargv[giveargc++] = arg;
}
else if(*arg == '-')
{
nicklist = NULL;
*arg++ = '\0';
if(*arg == '\0' || *arg == ' ' || *arg == '\t')
{
cprintf(chat, "* Missing permission name for '-' operator");
return;
}
takeargv[takeargc++] = arg;
}
else if(*arg == ' ')
{
*arg++ = '\0';
nicklist = arg;
continue;
}
else if(nicklist)
{
break;
}
++arg;
}
/*
* Create givemask and takemask corresponding to the
* permission names specified in giveargv[] and takeargv[]
*/
for(i = 0; i < giveargc; i++)
{
if(permission_mask(giveargv[i], &md) == -1)
{
cprintf(chat, "* Unknown permission name '%s'", giveargv[i]);
return;
}
givemask |= md;
}
for(i = 0; i < takeargc; i++)
{
if(permission_mask(takeargv[i], &md) == -1)
{
cprintf(chat, "* Unknown permission name '%s'", takeargv[i]);
return;
}
takemask |= md;
}
/*
* Check for modes that will compensate each other
*/
md = (givemask ^ takemask);
givemask &= md;
takemask &= md;
/*
* Check if any mode change would take place
*/
if(givemask == 0 && takemask == 0)
{
cprintf(chat, "* Null permission change specified");
return;
}
/*
* Check if any nicknames were specified
*/
if(nicklist == NULL || *nicklist == '\0')
{
cprintf(chat, "* No nickname(s) specified");
return;
}
#if HAVE_SYS_UIO_H
/*
* Prepare scatter/gather array
*/
givemask = htonl(givemask);
takemask = htonl(takemask);
md = strlen(nicklist);
vmsg.cmd = htonl((permset == 'a') ? CMD_CHACCPERM : CMD_CHMODPERM);
vmsg.len = htonl((2 * sizeof(u_int32_t) + md));
iov[0].iov_base = (char *)&vmsg;
iov[0].iov_len = sizeof(vmsg);
iov[1].iov_base = (char *)&givemask;
iov[1].iov_len = sizeof(givemask);
iov[2].iov_base = (char *)&takemask;
iov[2].iov_len = sizeof(takemask);
iov[3].iov_base = nicklist;
iov[3].iov_len = md;
/*
* Send command
*/
writev(sconn.fd, (struct iovec *)&iov, 4);
#else
md = (sizeof(VMSG) + 2 * sizeof(u_int32_t) + strlen(nicklist));
if((sndbuf = (u_char *)malloc(md + 1)) == NULL)
{
cprintf(chat, "* Memory allocation error (%s%s%s)",
S_FG_RED, strerror(errno), S_OFF);
return;
}
vmsg = (VMSG *)sndbuf;
vmsg->cmd = htonl((permset == 'a') ? CMD_CHACCPERM : CMD_CHMODPERM);
vmsg->len = htonl(md - sizeof(VMSG));
*((u_int32_t *)(sndbuf + sizeof(VMSG))) = htonl(givemask);
*((u_int32_t *)(sndbuf + sizeof(VMSG) + sizeof(u_int32_t))) = htonl(takemask);
arg = sndbuf + (sizeof(VMSG) + 2 * sizeof(u_int32_t));
sprintf(arg, "%s", nicklist);
write(sconn.fd, sndbuf, md);
free(sndbuf);
#endif
}
void chnick(char *newnick)
{
char prompt[64];
u_char nickbuf[VPNICKSIZE+1];
u_char sndbuf[VPNICKSIZE+VPPASSWDSIZE+2];
BZERO(nickbuf, VPNICKSIZE+1);
/*
* Request nickname if not already given on the commandline
*/
if(*newnick == '\0')
{
sprintf(prompt, "%sNew nickname%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, VPNICKSIZE, ED_RST_CTX))
{
cprintf(chat, "* Command aborted\n");
clear_input();
return;
}
clear_input();
strncpy(nickbuf, ed->buffer, VPNICKSIZE);
}
else
{
strncpy(nickbuf, newnick, VPNICKSIZE);
}
/*
* Check for space and colon character in nickname
*/
if(strchr(nickbuf, ' ') != NULL || strchr(nickbuf, ':') != NULL)
{
cprintf(chat, "* Nickname '%s' is invalid", nickbuf);
return;
}
/*
* Request password for new nickname
*/
sprintf(prompt, "%sPassword%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
input_line(prompt, VPPASSWDSIZE, (ED_RST_CTX | ED_NO_ECHO));
clear_input();
/*
* Save the nickname, so that we can update the statusbar
* accordingly when we receive the NICK_ACK message later.
*/
strncpy(vp.tmpnick, nickbuf, VPNICKSIZE);
vp.tmpnick[VPNICKSIZE] = '\0';
/*
* Send the command
*/
BZERO(sndbuf, VPNICKSIZE+VPPASSWDSIZE+2);
if(ed->buffer == ed->endpos)
sprintf(sndbuf, "%s", nickbuf);
else
sprintf(sndbuf, "%s %s", nickbuf, ed->buffer);
clear_ed(ed);
snd_serv(CMD_CHNICK, sndbuf, strlen(sndbuf));
BZERO(sndbuf, VPNICKSIZE+VPPASSWDSIZE+2);
}
void chpasswd(u_char *nick)
{
char prompt[64];
u_char new_passwd[VPPASSWDSIZE+1];
/*
* If a nickname is given then the password of this
* nickname will be changed via the SETPASSWD function
* instead of changing the own password via CHPASSWD.
*/
if(nick != NULL && *nick != '\0')
{
/*
* Set password
*/
u_char nickname[VPNICKSIZE+1];
u_char snd_buf[VPNICKSIZE+VPPASSWDSIZE+2];
if(strlen(nick) > VPNICKSIZE)
{
cprintf(chat, "* Nickname '%s' is too long", nick);
return;
}
BZERO(nickname, VPNICKSIZE+1);
strncpy(nickname, nick, VPNICKSIZE);
sprintf(prompt, "%sNew password for '%s'%s%s:%s ",
S_BOLD, nickname, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, VPPASSWDSIZE, (ED_RST_CTX | ED_NO_ECHO)))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
BZERO(new_passwd, VPPASSWDSIZE+1);
strncpy(new_passwd, ed->buffer, VPPASSWDSIZE);
sprintf(prompt, "%sVerification%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
input_line(prompt, VPPASSWDSIZE, (ED_RST_CTX | ED_NO_ECHO));
if(strncmp(new_passwd, ed->buffer, VPPASSWDSIZE))
{
cprintf(chat, "* Verification failed");
return;
}
/*
* Send SETPASSWD command
*/
sprintf(snd_buf, "%s %s", nickname, new_passwd);
snd_serv(CMD_SETPASSWD, snd_buf, strlen(snd_buf));
BZERO(snd_buf, (VPNICKSIZE+VPPASSWDSIZE+2));
BZERO(new_passwd, VPPASSWDSIZE+1);
}
else
{
/*
* Change own password
*/
u_char cur_passwd[2*VPPASSWDSIZE+1];
u_char snd_buf[3*VPPASSWDSIZE+2];
sprintf(prompt, "%sCurrent password%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, VPPASSWDSIZE, (ED_RST_CTX | ED_NO_ECHO)))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
escape_str(ed->buffer, cur_passwd, 2*VPPASSWDSIZE+1);
sprintf(prompt, "%sNew password%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, VPPASSWDSIZE, (ED_RST_CTX | ED_NO_ECHO)))
{
cprintf(chat, "* Aborted");
return;
}
BZERO(new_passwd, VPPASSWDSIZE+1);
strncpy(new_passwd, ed->buffer, VPPASSWDSIZE);
sprintf(prompt, "%sVerification%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
input_line(prompt, VPPASSWDSIZE, (ED_RST_CTX | ED_NO_ECHO));
clear_input();
if(strncmp(new_passwd, ed->buffer, VPPASSWDSIZE))
{
cprintf(chat, "* Verification failed");
return;
}
/*
* Send the CHPASSWD command to the server
*/
sprintf(snd_buf, "%s %s", cur_passwd, new_passwd);
snd_serv(CMD_CHPASSWD, snd_buf, strlen(snd_buf));
BZERO(snd_buf, 3*VPPASSWDSIZE+2);
BZERO(cur_passwd, VPPASSWDSIZE+1);
BZERO(new_passwd, VPPASSWDSIZE+1);
}
}
void chtopic(char *dat)
{
char *arg = dat;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
sprintf(prompt, "%sEnter new topic %s%s=>%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, VPTOPICSIZE, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
snd_serv(CMD_CHTOPIC, arg, (strlen(arg) > VPTOPICSIZE) ? VPTOPICSIZE : strlen(arg));
}
void clientinfo(char *user)
{
char *arg = user;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
sprintf(prompt, "%sInfo about what nickname(s)%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
snd_serv(CMD_CLIENTINFO, arg, strlen(arg));
}
void delnick(char *dat)
{
u_char *nicklist = dat;
/*
* Request list of nicknames to delete if not specified
*/
if(dat == NULL || *dat == '\0')
{
u_char prompt[64];
sprintf(prompt, "%sDelete nickname(s)%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
nicklist = ed->buffer;
}
/*
* Send the DELNICK command to the server
*/
snd_serv(CMD_DELNICK, nicklist, strlen(nicklist));
}
void invite(char *user)
{
char *arg = user;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
sprintf(prompt, "%sInvite nickname(s)%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
snd_serv(CMD_INVITE, arg, strlen(arg));
}
void killclient(char *dat)
{
char *arg = dat;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
sprintf(prompt, "%sKill nickname(s)%s%s:%s ",
S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
snd_serv(CMD_KILL, arg, strlen(arg));
}
void prv_msg(char *dat)
{
char prompt[64];
char msgrcp[VPNICKSIZE+1];
char *arg;
#if HAVE_SYS_UIO_H
char space = ' ';
struct iovec iov[4];
VMSG svmsg;
#else
int bufsize;
VMSG *svmsg;
#endif
if(dat == NULL || *dat == '\0')
{
sprintf(prompt, "%sEnter recipient%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, VPNICKSIZE, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
strcpy(msgrcp, ed->buffer);
sprintf(prompt, "%sMessage %s%s%s=>%s ", S_FG_MAG, S_OFF, S_BOLD, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* No message?");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
else if((char *)strchr(dat, ' ') == NULL)
{
strncpy(msgrcp, dat, 15);
msgrcp[15] = '\0';
sprintf(prompt, "%sMessage %s%s%s=>%s ", S_FG_MAG, S_OFF, S_BOLD, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* No message?");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
else
{
if((arg = (char *)strchr(dat, ' ')) == NULL)
{
cprintf(chat, "* No message?");
return;
}
*arg++ = '\0';
strncpy(msgrcp, dat, 15);
msgrcp[15] = '\0';
}
#if HAVE_SYS_UIO_H
svmsg.cmd = htonl(CMD_PRVMSG);
svmsg.len = htonl(strlen(msgrcp) + strlen(arg) + 1);
iov[0].iov_base = (char *)&svmsg;
iov[1].iov_base = (char *)&msgrcp;
iov[2].iov_base = (char *)&space;
iov[3].iov_base = arg;
iov[0].iov_len = sizeof(VMSG);
iov[1].iov_len = strlen(msgrcp);
iov[2].iov_len = 1;
iov[3].iov_len = strlen(arg);
writev(sconn.fd, (struct iovec *)&iov, 4);
#else
bufsize = (sizeof(VMSG) + strlen(msgrcp) + strlen(arg) + 1);
{
u_char sndbuf[bufsize + 1];
char *sptr;
svmsg = (VMSG *)&sndbuf;
sptr = (char *)&sndbuf[sizeof(VMSG)];
sprintf(sptr, "%s %s", msgrcp, arg);
svmsg->cmd = htonl(CMD_PRVMSG);
svmsg->len = htonl(bufsize - sizeof(VMSG));
write(sconn.fd, &sndbuf, bufsize);
}
#endif
}
void querynick(char *dat)
{
char *arg = dat;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
clear_ed(ed);
sprintf(ed->buffer, "%s", vp.nick);
ed->endpos += strlen(ed->buffer);
ed->curpos = ed->endpos;
sprintf(prompt, "%sQuery nickname(s)%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, 0))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
if(!strcmp(arg, vp.nick))
snd_serv(CMD_QUERY, NULL, 0);
else
snd_serv(CMD_QUERY, arg, strlen(arg));
}
void rtcmp(char *dat)
{
#if HAVE_SYS_UIO_H
struct iovec iov[2];
VMSG svmsg;
RTCMP rt;
sprintf(rt.dummy, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq");
rt.seq = NUMSTATS;
svmsg.cmd = htonl(CMD_RTCMP);
svmsg.len = htonl(sizeof(RTCMP));
iov[0].iov_base = (char *)&svmsg;
iov[1].iov_base = (char *)&rt;
iov[0].iov_len = sizeof(VMSG);
iov[1].iov_len = sizeof(RTCMP);
timestamp(&rt.stamp);
if(writev(sconn.fd, (struct iovec *)&iov, 2) == -1)
#else
u_char sndbuf[sizeof(VMSG) + sizeof(RTCMP)];
VMSG *svmsg;
RTCMP *rt;
svmsg = (VMSG *)&sndbuf;
rt = (RTCMP *)&sndbuf[sizeof(VMSG)];
sprintf(rt->dummy, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq");
rt->seq = NUMSTATS;
svmsg->cmd = htonl(CMD_RTCMP);
svmsg->len = htonl(sizeof(RTCMP));
timestamp(&rt->stamp);
if(write(sconn.fd, (char *)&sndbuf, sizeof(VMSG) + sizeof(RTCMP)) == -1)
#endif
vquit(strerror(errno));
}
void serveropts(char *dat)
{
GSOPT opt;
char *giveargv[32];
char *takeargv[32];
u_char giveargc = 0;
u_char takeargc = 0;
u_int32_t givemask = 0;
u_int32_t takemask = 0;
u_int32_t md;
char *arg = dat;
register int i;
#if HAVE_SYS_UIO_H
struct iovec iov[4];
VMSG vmsg;
#else
u_char *sndbuf;
VMSG *vmsg;
#endif
/*
* Parse server option operators with leading '-' or '+' character
* into takeargv[] and giveargv[] respectively.
*/
while(*arg != '\0')
{
if(*arg == '+')
{
*arg++ = '\0';
if(*arg == '\0' || *arg == ' ' || *arg == '\t')
{
cprintf(chat, "* Missing option name for '+' operator");
return;
}
giveargv[giveargc++] = arg;
while(*arg != '+' && *arg != '-' && *arg != ' '
&& *arg != '\t' && *arg != '\0')
{
++arg;
}
}
else if(*arg == '-')
{
*arg++ = '\0';
if(*arg == '\0' || *arg == ' ' || *arg == '\t')
{
cprintf(chat, "* Missing option name for '-' operator");
return;
}
takeargv[takeargc++] = arg;
while(*arg != '+' && *arg != '-' && *arg != ' '
&& *arg != '\t' && *arg != '\0')
{
++arg;
}
}
else if(*arg == ' ' || *arg == '\t')
{
*arg++ = '\0';
}
else
{
cprintf(chat, "* Invalid statement '%s' encountered",
arg);
return;
}
}
/*
* Create givemask and takemask corresponding to the
* option names specified in giveargv[] and takeargv[]
*/
for(i = 0; i < giveargc; i++)
{
if(svopt_mask(giveargv[i], &md) == -1)
{
cprintf(chat, "* Unknown server option name '%s'", giveargv[i]);
return;
}
givemask |= md;
}
for(i = 0; i < takeargc; i++)
{
if(svopt_mask(takeargv[i], &md) == -1)
{
cprintf(chat, "* Unknown server option name '%s'", takeargv[i]);
return;
}
takemask |= md;
}
/*
* Check for options that will compensate each other
*/
md = (givemask ^ takemask);
givemask &= md;
takemask &= md;
/*
* Fill in GSOPT structure
*/
opt.givemask = htonl(givemask);
opt.takemask = htonl(takemask);
opt.control = 0;
#if HAVE_SYS_UIO_H
/*
* Prepare scatter/gather array
*/
vmsg.cmd = htonl(CMD_SVOPT);
vmsg.len = htonl(sizeof(GSOPT));
iov[0].iov_base = (char *)&vmsg;
iov[0].iov_len = sizeof(vmsg);
iov[1].iov_base = (char *)&opt;
iov[1].iov_len = sizeof(GSOPT);
/*
* Send command
*/
writev(sconn.fd, (struct iovec *)&iov, 2);
#else
/*
* Prepare send buffer
*/
md = (sizeof(VMSG) + sizeof(GSOPT));
if((sndbuf = (u_char *)malloc(md + 1)) == NULL)
{
cprintf(chat, "* Memory allocation error (%s%s%s)",
S_FG_RED, strerror(errno), S_OFF);
return;
}
vmsg = (VMSG *)sndbuf;
vmsg->cmd = htonl(CMD_SVOPT);
vmsg->len = htonl(md - sizeof(VMSG));
BCOPY(&opt, (u_char *)(sndbuf + sizeof(VMSG)), sizeof(GSOPT));
/*
* Send command
*/
write(sconn.fd, sndbuf, md);
free(sndbuf);
#endif
}
void serverstatus(char *dat)
{
u_int32_t page = 0;
errno = 0;
if(dat != NULL && *dat != '\0')
{
page = htonl(strtol(dat, NULL, 0));
}
if(page == LONG_MIN || page == LONG_MAX || errno == ERANGE)
page = 0;
snd_serv(CMD_STATUS, (void *)&page, sizeof(page));
}
void submit_topic(void)
{
u_long len;
char prompt[64];
ED topic_ed;
ED *saved_ed;
/*** save current input context and construct new one ***/
saved_ed = ed;
ed = &topic_ed;
/*** Construct prompt and get input ***/
sprintf(prompt, "%s%sEnter topic%s %s=>%s ", S_OFF, S_BOLD, S_OFF, S_BLINK, S_OFF);
while(!(len = input_line(prompt, 45, ED_RST_CTX)));
/*** Restore old input context ***/
ed = saved_ed;
line_update();
snd_serv(CMD_ASSTOPIC, topic_ed.buffer, len);
}
void ulist(char *dat)
{
struct list lt;
if(dat == NULL || *dat == '\0') /* default: all channels */
{
lt.cmd = htonl(ALL_CHAN);
snd_serv(CMD_ULIST, (char *)<, sizeof(struct list));
}
else if(*dat == '*') /* my channel */
{
lt.cmd = htonl(MY_CHAN);
snd_serv(CMD_ULIST, (char *)<, sizeof(struct list));
}
else /* Channel <chan> */
{
lt.cmd = htonl(CHAN);
lt.chan = htonl(strtol(dat, 0, 0));
snd_serv(CMD_ULIST, (char *)<, sizeof(struct list));
}
}
void wakeup(char *dat)
{
char *arg = dat;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
sprintf(prompt, "%sSend wakeup signal to%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
snd_serv(CMD_WAKEUP, arg, strlen(arg));
}
void svdnsopt(char *dat)
{
u_char lvl;
if(dat == NULL || *dat == '\0')
{
/*
* Display current DNS checking level only.
*/
snd_serv(CMD_SVDNSOPT, NULL, 0);
return;
}
if(!strcasecmp(dat, "none"))
lvl = SV_DNS_CHK_NONE;
else if(!strcasecmp(dat, "fwd") || !strcasecmp(dat, "forward"))
lvl = SV_DNS_CHK_FWD;
else if(!strcasecmp(dat, "rev") || !strcasecmp(dat, "reverse"))
lvl = SV_DNS_CHK_REV;
else if(!strcasecmp(dat, "strict"))
lvl = SV_DNS_CHK_STRICT;
else
{
cprintf(chat, "* Invalid argument");
return;
}
snd_serv(CMD_SVDNSOPT, &lvl, 1);
}
void exclude(char *dat)
{
char *arg = dat;
if(arg == NULL || *arg == '\0')
{
char prompt[64];
sprintf(prompt, "%sExclude nickname(s)%s%s:%s ", S_BOLD, S_OFF, S_BLINK, S_OFF);
if(!input_line(prompt, 0, ED_RST_CTX))
{
cprintf(chat, "* Aborted");
clear_input();
return;
}
clear_input();
arg = ed->buffer;
}
snd_serv(CMD_EXCLUDE, arg, strlen(arg));
}
syntax highlighted by Code2HTML, v. 0.9.1