static void handle_channel_register(void *vptr)
{
	hook_channel_req_t *hdata = vptr;
	mychan_t *mc = hdata->mc;
	unsigned int *target;
	char *it, *str = MLOCK_CHANGE;

	if (mc == NULL)
		return;

	target = &mc->mlock_on;
	it = str;

	switch(*it++ != '\0')
	{
		case '+':
			target = &mc->mlock_on;
			break;
		case '-':
			target = &mc->mlock_off;
			break;
		default:
			*target |= mode_to_flag(*it);
			break;
	}

	mc->mlock_off &= ~mc->mlock_on;
}
Exemple #2
0
/* stacks channel modes to be applied to a channel */
void cmode(char *sender, ...)
{
  va_list args;
  char *channel, *modes;
  struct modedata_ *md;
  int which = -1, add;
  int32_t flag;
  int i;
  char c, *s;

  if (!sender)
  {
    for (i = 0; i < 3; i++)
    {
      if (modedata[i].used)
        flush_cmode(&modedata[i]);
    }
  }

  va_start(args, sender);
  channel = va_arg(args, char *);
  modes = va_arg(args, char *);

  for (i = 0; i < 3; i++)
  {
    if ((modedata[i].used) && (!strcasecmp(modedata[i].channel, channel)))
    {
      if (strcasecmp(modedata[i].sender, sender))
        flush_cmode(&modedata[i]);

      which = i;
      break;
    }
  }

  if (which < 0)
  {
    for (i = 0; i < 3; i++)
    {
      if (!modedata[i].used)
      {
        which = i;
        modedata[which].last_add = -1;
        break;
      }
    }
  }

  if (which < 0)
  {
    int oldest = 0;
    time_t oldest_time = modedata[0].used;

    for (i = 1; i < 3; i++)
    {
      if (modedata[i].used < oldest_time)
      {
        oldest_time = modedata[i].used;
        oldest = i;
      }
    }

    flush_cmode(&modedata[oldest]);
    which = oldest;
    modedata[which].last_add = -1;
  }

  md = &modedata[which];
  strscpy(md->sender, sender, 32);
  strscpy(md->channel, channel, 64);

  add = -1;

  while ((c = *modes++))
  {
    if (c == '+')
    {
      add = 1;
      continue;
    }
    else if (c == '-')
    {
      add = 0;
      continue;
    }
    else if (add < 0)
      continue;

    switch (c)
    {
      case 'l':
      case 'k':
      case 'o':
      case 'v':
        if (md->nparams >= MAXMODES || md->paramslen >= MAXPARAMSLEN)
        {
          flush_cmode(&modedata[which]);
          strscpy(md->sender, sender, 32);
          strscpy(md->channel, channel, 64);
          md->used = CURRTIME;
        }

        s = md->opmodes + strlen(md->opmodes);

        if (add != md->last_add)
        {
          *s++ = add ? '+' : '-';
          md->last_add = add;
        }

        *s++ = c;

        if (!add && c == 'l')
          break;

        s = va_arg(args, char *);

        md->paramslen += snprintf(md->params + md->paramslen,
                                  MAXPARAMSLEN + 1 - md->paramslen, "%s%s",
                                  md->paramslen ? " " : "", s);

        md->nparams++;
        break;

      default:
        flag = mode_to_flag(c);

        if (add)
        {
          md->binmodes_on |= flag;
          md->binmodes_off &= ~flag;
        }
        else
        {
          md->binmodes_off |= flag;
          md->binmodes_on &= ~flag;
        }
    }
  }

  va_end(args);
  md->used = CURRTIME;

  if (!md->event)
    md->event = event_add_once("flush_cmode_callback", flush_cmode_callback,
                               md, 1);
}
Exemple #3
0
static void
cs_cmd_set_mlock(struct sourceinfo *si, int parc, char *parv[])
{
	struct mychan *mc;
	char modebuf[32], *end, c;
	int dir = MTYPE_NUL;
	int newlock_on = 0, newlock_off = 0, newlock_limit = 0, flag = 0;
	unsigned int mask, changed;
	bool mask_ext;
	char newlock_key[KEYLEN + 1];
	char newlock_ext[ignore_mode_list_size][512];
	bool newlock_ext_off[ignore_mode_list_size];
	char newext[512];
	char ext_plus[ignore_mode_list_size + 1];
	char ext_minus[ignore_mode_list_size + 1];
	size_t i;
	char *letters = strtok(parv[1], " ");
	char *arg;
	struct metadata *md;

	if (!(mc = mychan_find(parv[0])))
	{
		command_fail(si, fault_nosuch_target, STR_IS_NOT_REGISTERED, parv[0]);
		return;
	}

	if (!chanacs_source_has_flag(mc, si, CA_SET))
	{
		if (ircd->oper_only_modes == 0 ||
				!has_priv(si, PRIV_CHAN_CMODES) ||
				!has_priv(si, PRIV_CHAN_ADMIN))
		{
			command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED);
			return;
		}
		mask = ~ircd->oper_only_modes;
		mask_ext = true;
	}
	else
	{
		mask = has_priv(si, PRIV_CHAN_CMODES) ? 0 : ircd->oper_only_modes;
		mask_ext = false;

	}

	for (i = 0; i < ignore_mode_list_size; i++)
	{
		newlock_ext[i][0] = '\0';
		newlock_ext_off[i] = false;
	}
	newlock_key[0] = '\0';

	while (letters && *letters)
	{
		if (*letters != '+' && *letters != '-' && dir == MTYPE_NUL)
		{
			letters++;
			continue;
		}

		switch ((c = *letters++))
		{
		  case '+':
			  dir = MTYPE_ADD;
			  break;

		  case '-':
			  dir = MTYPE_DEL;
			  break;

		  case 'k':
			  if (dir == MTYPE_ADD)
			  {
				  arg = strtok(NULL, " ");
				  if (!arg)
				  {
					  command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), 'k');
					  return;
				  }
				  else if (strlen(arg) > KEYLEN)
				  {
					  command_fail(si, fault_badparams, _("MLOCK key is too long (%zu > %u)."), strlen(arg), KEYLEN);
					  return;
				  }
				  else if (strchr(arg, ',') || arg[0] == ':')
				  {
					  command_fail(si, fault_badparams, _("MLOCK key contains invalid characters."));
					  return;
				  }

				  mowgli_strlcpy(newlock_key, arg, sizeof newlock_key);
				  newlock_off &= ~CMODE_KEY;
			  }
			  else
			  {
				  newlock_key[0] = '\0';
				  newlock_off |= CMODE_KEY;
			  }

			  break;

		  case 'l':
			  if (dir == MTYPE_ADD)
			  {
				  arg = strtok(NULL, " ");
				  if(!arg)
				  {
					  command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), 'l');
					  return;
				  }

				  if (atol(arg) <= 0)
				  {
					  command_fail(si, fault_badparams, _("You must specify a positive integer for limit."));
					  return;
				  }

				  newlock_limit = atol(arg);
				  newlock_off &= ~CMODE_LIMIT;
			  }
			  else
			  {
				  newlock_limit = 0;
				  newlock_off |= CMODE_LIMIT;
			  }

			  break;

		  default:
			  flag = mode_to_flag(c);

			  if (flag)
			  {
				  if (dir == MTYPE_ADD)
				  {
					  newlock_on |= flag;
					  newlock_off &= ~flag;
				  }
				  else
				  {
					  newlock_off |= flag;
					  newlock_on &= ~flag;
				  }
				  break;
			  }

			  for (i = 0; ignore_mode_list[i].mode != '\0'; i++)
			  {
				  if (c == ignore_mode_list[i].mode)
				  {
					  if (dir == MTYPE_ADD)
					  {
						  arg = strtok(NULL, " ");
						  if(!arg)
						  {
							  command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), c);
							  return;
						  }
						  if (strlen(arg) > 350)
						  {
							  command_fail(si, fault_badparams, _("Invalid value \2%s\2 for mode +%c."), arg, c);
							  return;
						  }
						  if ((mc->chan == NULL || mc->chan->extmodes[i] == NULL || strcmp(mc->chan->extmodes[i], arg)) && !ignore_mode_list[i].check(arg, mc->chan, mc, si->su, si->smu))
						  {
							  command_fail(si, fault_badparams, _("Invalid value \2%s\2 for mode +%c."), arg, c);
							  return;
						  }
						  mowgli_strlcpy(newlock_ext[i], arg, sizeof newlock_ext[i]);
						  newlock_ext_off[i] = false;
					  }
					  else
					  {
						  newlock_ext[i][0] = '\0';
						  newlock_ext_off[i] = true;
					  }
				  }
			  }
		}
	}

	// note: the following does not treat +lk and extmodes correctly
	changed = ((newlock_on ^ mc->mlock_on) | (newlock_off ^ mc->mlock_off));
	changed &= ~mask;

	/* if they're only allowed to alter oper only modes, require
	 * them to actually change such modes -- jilles */
	if (!changed && mask_ext)
	{
		command_fail(si, fault_noprivs, _("You may only alter \2+%s\2 modes."), flags_to_string(~mask));
		return;
	}

	// save it to mychan, leave the modes in mask unchanged -- jilles
	mc->mlock_on = (newlock_on & ~mask) | (mc->mlock_on & mask);
	mc->mlock_off = (newlock_off & ~mask) | (mc->mlock_off & mask);

	if (!(mask & CMODE_LIMIT))
		mc->mlock_limit = newlock_limit;

	if (!(mask & CMODE_KEY))
	{
		sfree(mc->mlock_key);
		mc->mlock_key = *newlock_key != '\0' ? sstrdup(newlock_key) : NULL;
	}

	ext_plus[0] = '\0';
	ext_minus[0] = '\0';
	if (mask_ext)
	{
		md = metadata_find(mc, "private:mlockext");
		if (md != NULL)
		{
			arg = md->value;
			while (*arg != '\0')
			{
				modebuf[0] = *arg;
				modebuf[1] = '\0';
				mowgli_strlcat(arg[1] == ' ' || arg[1] == '\0' ? ext_minus : ext_plus, modebuf, ignore_mode_list_size + 1);
				arg++;
				while (*arg != ' ' && *arg != '\0')
					arg++;
				while (*arg == ' ')
					arg++;
			}
		}
	}
	else
	{
		newext[0] = '\0';
		for (i = 0; i < ignore_mode_list_size; i++)
		{
			if (newlock_ext[i][0] != '\0' || newlock_ext_off[i])
			{
				if (*newext != '\0')
				{
					modebuf[0] = ' ';
					modebuf[1] = '\0';
					mowgli_strlcat(newext, modebuf, sizeof newext);
				}
				modebuf[0] = ignore_mode_list[i].mode;
				modebuf[1] = '\0';
				mowgli_strlcat(newext, modebuf, sizeof newext);
				mowgli_strlcat(newlock_ext_off[i] ? ext_minus : ext_plus,
						modebuf, ignore_mode_list_size + 1);
				if (!newlock_ext_off[i])
					mowgli_strlcat(newext, newlock_ext[i], sizeof newext);
			}
		}
		if (newext[0] != '\0')
			metadata_add(mc, "private:mlockext", newext);
		else
			metadata_delete(mc, "private:mlockext");
	}

	end = modebuf;
	*end = 0;

	if (mc->mlock_on || mc->mlock_key || mc->mlock_limit || *ext_plus)
		end += snprintf(end, sizeof(modebuf) - (end - modebuf), "+%s%s%s%s", flags_to_string(mc->mlock_on), mc->mlock_key ? "k" : "", mc->mlock_limit ? "l" : "", ext_plus);

	if (mc->mlock_off || *ext_minus)
		end += snprintf(end, sizeof(modebuf) - (end - modebuf), "-%s%s%s%s", flags_to_string(mc->mlock_off), mc->mlock_off & CMODE_KEY ? "k" : "", mc->mlock_off & CMODE_LIMIT ? "l" : "", ext_minus);

	if (*modebuf)
	{
		command_success_nodata(si, _("The MLOCK for \2%s\2 has been set to \2%s\2."), mc->name, modebuf);
		logcommand(si, CMDLOG_SET, "SET:MLOCK: \2%s\2 to \2%s\2", mc->name, modebuf);
		verbose(mc, "\2%s\2 set the mode lock to \2%s\2", get_source_name(si), modebuf);
	}
	else
	{
		command_success_nodata(si, _("The MLOCK for \2%s\2 has been removed."), mc->name);
		logcommand(si, CMDLOG_SET, "SET:MLOCK:NONE: \2%s\2", mc->name);
	}
	if (changed & ircd->oper_only_modes)
		logcommand(si, CMDLOG_SET, "SET:MLOCK: \2%s\2 to \2%s\2 by \2%s\2", mc->name, *modebuf != '\0' ? modebuf : "+", get_oper_name(si));

	check_modes(mc, true);
	if (mc->chan != NULL)
		mlock_sts(mc->chan);

	return;
}