/****************************************************************************** * 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 #include #include #if HAVE_SYS_UIO_H # include #endif #include #include /*** 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]
[ttl] - add an ACL rule to the database", S_FG_GRN, S_OFF); cprintf(chat, "* %s.A%s delete - 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%s - a rule number in the range 0..65534", S_BOLD, S_OFF); cprintf(chat, "* %s%s - action to be taken by this rule (accept|reject)", S_BOLD, S_OFF); cprintf(chat, "* %s
%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 <-/+perm> ... ...", S_FG_GRN, S_OFF); cprintf(chat, "*\n* %sWhere:%s", S_UL, S_OFF); cprintf(chat, "*\n* - 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, "* - 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 */ { 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)); }