unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
mode.c (47037B)
1 /* 2 * IRC - Internet Relay Chat, src/modules/mode.c 3 * (C) 2005-.. The UnrealIRCd Team 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 #include "unrealircd.h" 24 25 ModuleHeader MOD_HEADER 26 = { 27 "mode", 28 "5.0", 29 "command /mode", 30 "UnrealIRCd Team", 31 "unrealircd-6", 32 }; 33 34 /* Forward declarations */ 35 int list_mode_request(Client *client, Channel *channel, const char *req); 36 CMD_FUNC(cmd_mode); 37 CMD_FUNC(cmd_mlock); 38 void _do_mode(Channel *channel, Client *client, MessageTag *recv_mtags, int parc, const char *parv[], time_t sendts, int samode); 39 MultiLineMode *_set_mode(Channel *channel, Client *client, int parc, const char *parv[], u_int *pcount, 40 char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]); 41 void _set_channel_mode(Channel *channel, MessageTag *mtags, const char *modes, const char *parameters); 42 CMD_FUNC(_cmd_umode); 43 44 /* local: */ 45 int do_mode_char(Channel *channel, long modetype, char modechar, const char *param, 46 u_int what, Client *client, 47 u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]); 48 int do_extmode_char(Channel *channel, Cmode *handler, const char *param, u_int what, 49 Client *client, u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]); 50 void do_mode_char_member_mode_new(Channel *channel, Cmode *handler, const char *param, u_int what, 51 Client *client, u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]); 52 MultiLineMode *make_mode_str(Client *client, Channel *channel, Cmode_t oldem, int pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]); 53 54 static char *mode_cutoff(const char *s); 55 void mode_operoverride_msg(Client *client, Channel *channel, char *modebuf, char *parabuf); 56 57 static int samode_in_progress = 0; 58 59 MOD_TEST() 60 { 61 MARK_AS_OFFICIAL_MODULE(modinfo); 62 EfunctionAddVoid(modinfo->handle, EFUNC_DO_MODE, _do_mode); 63 EfunctionAddPVoid(modinfo->handle, EFUNC_SET_MODE, TO_PVOIDFUNC(_set_mode)); 64 EfunctionAddVoid(modinfo->handle, EFUNC_CMD_UMODE, _cmd_umode); 65 EfunctionAddVoid(modinfo->handle, EFUNC_SET_CHANNEL_MODE, _set_channel_mode); 66 return MOD_SUCCESS; 67 } 68 69 MOD_INIT() 70 { 71 CommandAdd(modinfo->handle, "MODE", cmd_mode, MAXPARA, CMD_USER|CMD_SERVER); 72 CommandAdd(modinfo->handle, MSG_MLOCK, cmd_mlock, MAXPARA, CMD_SERVER); 73 MARK_AS_OFFICIAL_MODULE(modinfo); 74 return MOD_SUCCESS; 75 } 76 77 MOD_LOAD() 78 { 79 return MOD_SUCCESS; 80 } 81 82 MOD_UNLOAD() 83 { 84 return MOD_SUCCESS; 85 } 86 87 /* 88 * cmd_mode -- written by binary (garryb@binary.islesfan.net) 89 * Completely rewrote it. The old mode command was 820 lines of ICKY 90 * coding, which is a complete waste, because I wrote it in 570 lines of 91 * *decent* coding. This is also easier to read, change, and fine-tune. Plus, 92 * everything isn't scattered; everything's grouped where it should be. 93 * 94 * parv[1] - channel 95 */ 96 CMD_FUNC(cmd_mode) 97 { 98 long unsigned sendts = 0; 99 Ban *ban; 100 Channel *channel; 101 102 /* Now, try to find the channel in question */ 103 if (parc > 1) 104 { 105 if (*parv[1] == '#') 106 { 107 channel = find_channel(parv[1]); 108 if (!channel) 109 { 110 CALL_CMD_FUNC(cmd_umode); 111 return; 112 } 113 } else 114 { 115 CALL_CMD_FUNC(cmd_umode); 116 return; 117 } 118 } else 119 { 120 sendnumeric(client, ERR_NEEDMOREPARAMS, "MODE"); 121 return; 122 } 123 124 if (MyConnect(client) && !valid_channelname(parv[1])) 125 { 126 sendnumeric(client, ERR_NOSUCHCHANNEL, parv[1]); 127 return; 128 } 129 130 if (parc < 3) 131 { 132 char modebuf[BUFSIZE], parabuf[BUFSIZE]; 133 *modebuf = *parabuf = '\0'; 134 135 modebuf[1] = '\0'; 136 channel_modes(client, modebuf, parabuf, sizeof(modebuf), sizeof(parabuf), channel, 0); 137 sendnumeric(client, RPL_CHANNELMODEIS, channel->name, modebuf, parabuf); 138 sendnumeric(client, RPL_CREATIONTIME, channel->name, (long long)channel->creationtime); 139 return; 140 } 141 142 /* List mode request? Eg: "MODE #channel b" to list all bans */ 143 if (MyUser(client) && BadPtr(parv[3]) && list_mode_request(client, channel, parv[2])) 144 return; 145 146 opermode = 0; 147 148 #ifndef NO_OPEROVERRIDE 149 if (IsUser(client) && !IsULine(client) && !check_channel_access(client, channel, "oaq") && 150 !check_channel_access(client, channel, "h") && ValidatePermissionsForPath("channel:override:mode",client,NULL,channel,NULL)) 151 { 152 sendts = 0; 153 opermode = 1; 154 goto aftercheck; 155 } 156 157 if (IsUser(client) && !IsULine(client) && !check_channel_access(client, channel, "oaq") && 158 check_channel_access(client, channel, "h") && ValidatePermissionsForPath("channel:override:mode",client,NULL,channel,NULL)) 159 { 160 opermode = 2; 161 goto aftercheck; 162 } 163 #endif 164 165 /* User does not have permission to use the MODE command */ 166 if (MyUser(client) && !IsULine(client) && !check_channel_access(client, channel, "hoaq") && 167 !ValidatePermissionsForPath("channel:override:mode",client,NULL,channel,NULL)) 168 { 169 sendnumeric(client, ERR_CHANOPRIVSNEEDED, channel->name); 170 return; 171 } 172 173 if (parv[2] && (*parv[2] == '&')) 174 { 175 /* We don't do any bounce-mode handling anymore since UnrealIRCd 6 */ 176 return; 177 } 178 179 if (IsServer(client) && (sendts = atol(parv[parc - 1])) && 180 !IsULine(client) && (sendts > channel->creationtime)) 181 { 182 unreal_log(ULOG_INFO, "mode", "MODE_TS_IGNORED", client, 183 "MODE change ignored for $channel from $client: " 184 "timestamp mismatch, ours=$channel.creationtime, theirs=$their_ts", 185 log_data_channel("channel", channel), 186 log_data_integer("their_ts", sendts)); 187 return; 188 } 189 if (IsServer(client) && !sendts && *parv[parc - 1] != '0') 190 sendts = -1; 191 if (IsServer(client) && sendts != -1) 192 parc--; /* server supplied a time stamp, remove it now */ 193 194 aftercheck: 195 196 /* This is to prevent excess +<whatever> modes. -- Syzop */ 197 if (MyUser(client) && parv[2]) 198 { 199 parv[2] = mode_cutoff(parv[2]); 200 } 201 202 /* Filter out the unprivileged FIRST. * 203 * Now, we can actually do the mode. */ 204 205 (void)do_mode(channel, client, recv_mtags, parc - 2, parv + 2, sendts, 0); 206 /* After this don't touch 'channel' anymore, as permanent module may have destroyed the channel */ 207 opermode = 0; /* Important since sometimes forgotten. -- Syzop */ 208 } 209 210 /** Cut off mode string (eg: +abcdfjkdsgfgs) at MAXMODEPARAMS modes. 211 * @param s The mode string (modes only, no parameters) 212 * @note Should only used on local clients 213 * @returns The cleaned up string 214 */ 215 static char *mode_cutoff(const char *i) 216 { 217 static char newmodebuf[BUFSIZE]; 218 char *o; 219 unsigned short modesleft = MAXMODEPARAMS * 2; /* be generous... */ 220 221 strlcpy(newmodebuf, i, sizeof(newmodebuf)); 222 223 for (o = newmodebuf; *o && modesleft; o++) 224 if ((*o != '-') && (*o != '+')) 225 modesleft--; 226 *o = '\0'; 227 return newmodebuf; 228 } 229 230 /* do_mode -- written by binary 231 * User or server is authorized to do the mode. This takes care of 232 * setting the mode and relaying it to other users and servers. 233 */ 234 void _do_mode(Channel *channel, Client *client, MessageTag *recv_mtags, int parc, const char *parv[], time_t sendts, int samode) 235 { 236 Client *orig_client = client; /* (needed for samode replacement in a loop) */ 237 char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]; 238 int pcount; 239 int i; 240 char tschange = 0; 241 MultiLineMode *m; 242 243 /* Please keep the next 3 lines next to each other */ 244 samode_in_progress = samode; 245 m = set_mode(channel, client, parc, parv, &pcount, pvar); 246 samode_in_progress = 0; 247 248 if (IsServer(client)) 249 { 250 if (sendts > 0) 251 { 252 if (IsInvalidChannelTS(sendts)) 253 { 254 unreal_log(ULOG_WARNING, "mode", "MODE_INVALID_TIMESTAMP", client, 255 "MODE for channel $channel has invalid timestamp $send_timestamp (from $client.name)\n" 256 "Buffer: $modebuf $parabuf", 257 log_data_channel("channel", channel), 258 log_data_integer("send_timestamp", sendts), 259 log_data_string("modebuf", m?m->modeline[0]:""), 260 log_data_string("parabuf", m?m->modeline[0]:"")); 261 /* Yeah, so what to do in this case? 262 * Don't set channel->creationtime 263 * and assume merging. 264 */ 265 sendts = channel->creationtime; 266 } else 267 if (sendts < channel->creationtime) 268 { 269 /* Our timestamp is wrong or this is a new channel */ 270 tschange = 1; 271 channel->creationtime = sendts; 272 273 } 274 if (sendts > channel->creationtime && channel->creationtime) 275 { 276 /* Their timestamp is wrong */ 277 sendts = channel->creationtime; 278 sendto_one(client, NULL, ":%s MODE %s + %lld", me.name, 279 channel->name, (long long)channel->creationtime); 280 } 281 } 282 if (sendts == -1) 283 sendts = channel->creationtime; 284 } 285 286 if (!m) 287 { 288 /* No modes changed (empty mode change) */ 289 if (tschange && !m) 290 { 291 /* Message from the other server is an empty mode, BUT they 292 * did change the channel->creationtime to an earlier TS 293 * (see above "Our timestamp is wrong or this is a new channel"). 294 * We need to relay this MODE message to all other servers 295 * (all except from where it came from, client). 296 */ 297 sendto_server(client, 0, 0, NULL, ":%s MODE %s + %lld", 298 me.id, channel->name, 299 (long long)channel->creationtime); 300 } 301 /* Nothing to send */ 302 safe_free_multilinemode(m); 303 opermode = 0; 304 return; 305 } 306 307 /* Now loop through the multiline modes... */ 308 for (i = 0; i < m->numlines; i++) 309 { 310 char *modebuf = m->modeline[i]; 311 char *parabuf = m->paramline[i]; 312 MessageTag *mtags = NULL; 313 int should_destroy = 0; 314 315 if (IsUser(orig_client) && samode && MyUser(orig_client)) 316 { 317 if (!sajoinmode) 318 { 319 char buf[512]; 320 snprintf(buf, sizeof(buf), "%s%s%s", modebuf, *parabuf ? " " : "", parabuf); 321 unreal_log(ULOG_INFO, "samode", "SAMODE_COMMAND", orig_client, 322 "Client $client used SAMODE $channel ($mode)", 323 log_data_channel("channel", channel), 324 log_data_string("mode", buf)); 325 } 326 327 client = &me; 328 sendts = 0; 329 } 330 331 if (m->numlines == 1) 332 { 333 /* Single mode lines are easy: retain original msgid etc */ 334 new_message(client, recv_mtags, &mtags); 335 } else { 336 /* We have a multi-mode line: 337 * This only happens when the input was a single mode line 338 * that got expanded into a multi mode line due to expansion 339 * issues. The sender could be a local client, but could also 340 * be a remote server like UnrealIRCd 5. 341 * We can't use the same msgid multiple times, and (if the 342 * sender was a server) then we can't use the original msgid 343 * either, not for both events and not for the first event 344 * (since the modeline differs for all events, including first). 345 * Obviously message ids must be unique for the event... 346 * So here is our special version again, just like we use in 347 * SJOIN and elsewhere sporadically for cases like this: 348 */ 349 new_message_special(client, recv_mtags, &mtags, ":%s MODE %s %s %s", client->name, channel->name, modebuf, parabuf); 350 } 351 352 /* IMPORTANT: if you return, don't forget to free mtags!! */ 353 354 if (MyConnect(client)) 355 RunHook(HOOKTYPE_PRE_LOCAL_CHANMODE, client, channel, mtags, modebuf, parabuf, sendts, samode); 356 else 357 RunHook(HOOKTYPE_PRE_REMOTE_CHANMODE, client, channel, mtags, modebuf, parabuf, sendts, samode); 358 359 /* opermode for twimodesystem --sts */ 360 #ifndef NO_OPEROVERRIDE 361 if ((opermode == 1) && IsUser(client)) 362 { 363 mode_operoverride_msg(client, channel, modebuf, parabuf); 364 365 sendts = 0; 366 } 367 #endif 368 369 sendto_channel(channel, client, NULL, 0, 0, SEND_LOCAL, mtags, 370 ":%s MODE %s %s %s", 371 client->name, channel->name, modebuf, parabuf); 372 373 if (IsServer(client) || IsMe(client)) 374 { 375 sendto_server(client, 0, 0, mtags, 376 ":%s MODE %s %s %s %lld", 377 client->id, channel->name, 378 modebuf, parabuf, 379 (sendts != -1) ? (long long)sendts : 0LL); 380 } else 381 { 382 sendto_server(client, 0, 0, mtags, 383 ":%s MODE %s %s %s", 384 client->id, channel->name, 385 modebuf, parabuf); 386 } 387 388 if (MyConnect(client)) 389 RunHook(HOOKTYPE_LOCAL_CHANMODE, client, channel, mtags, modebuf, parabuf, sendts, samode, &should_destroy); 390 else 391 RunHook(HOOKTYPE_REMOTE_CHANMODE, client, channel, mtags, modebuf, parabuf, sendts, samode, &should_destroy); 392 393 free_message_tags(mtags); 394 395 if (should_destroy) 396 break; /* eg channel went -P with nobody in it. 'channel' is freed now */ 397 } 398 safe_free_multilinemode(m); 399 opermode = 0; 400 } 401 402 /* make_mode_str -- written by binary 403 * Reconstructs the mode string, to make it look clean. mode_buf will 404 * contain the +x-y stuff, and the parabuf will contain the parameters. 405 */ 406 MultiLineMode *make_mode_str(Client *client, Channel *channel, Cmode_t oldem, int pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]) 407 { 408 Cmode *cm; 409 int what; 410 int cnt, z, i; 411 MultiLineMode *m = safe_alloc(sizeof(MultiLineMode)); 412 int curr = 0; 413 int initial_len; 414 415 if (client->user) 416 initial_len = strlen(client->name) + strlen(client->user->username) + strlen(GetHost(client)) + strlen(channel->name) + 11; 417 else 418 initial_len = strlen(client->name) + strlen(channel->name) + 11; 419 420 /* Reserve room for the first element */ 421 curr = 0; 422 m->modeline[curr] = safe_alloc(BUFSIZE); 423 m->paramline[curr] = safe_alloc(BUFSIZE); 424 m->numlines = curr+1; 425 what = 0; 426 427 /* The first element will be filled with all paramless modes. 428 * That is: both the ones that got set, and the ones that got unset. 429 * This will always fit. 430 */ 431 432 /* Which paramless modes got set? Eg +snt */ 433 for (cm=channelmodes; cm; cm = cm->next) 434 { 435 if (!cm->letter || cm->paracount) 436 continue; 437 /* have it now and didn't have it before? */ 438 if ((channel->mode.mode & cm->mode) && 439 !(oldem & cm->mode)) 440 { 441 if (what != MODE_ADD) 442 { 443 strlcat_letter(m->modeline[curr], '+', BUFSIZE); 444 what = MODE_ADD; 445 } 446 strlcat_letter(m->modeline[curr], cm->letter, BUFSIZE); 447 } 448 } 449 450 /* Which paramless modes got unset? Eg -r */ 451 for (cm=channelmodes; cm; cm = cm->next) 452 { 453 if (!cm->letter || cm->unset_with_param) 454 continue; 455 /* don't have it now and did have it before */ 456 if (!(channel->mode.mode & cm->mode) && (oldem & cm->mode)) 457 { 458 if (what != MODE_DEL) 459 { 460 strlcat_letter(m->modeline[curr], '-', BUFSIZE); 461 what = MODE_DEL; 462 } 463 strlcat_letter(m->modeline[curr], cm->letter, BUFSIZE); 464 } 465 } 466 467 /* Now for parameter modes we do both addition and removal. Eg +b-e ban!x@y exempt!z@z */ 468 for (cnt = 0; cnt < pcount; cnt++) 469 { 470 if ((strlen(m->modeline[curr]) + strlen(m->paramline[curr]) + strlen(&pvar[cnt][2])) > 507) 471 { 472 if (curr == MAXMULTILINEMODES) 473 { 474 /* Should be impossible.. */ 475 unreal_log(ULOG_ERROR, "mode", "MODE_MULTILINE_EXCEEDED", client, 476 "A mode string caused an avalanche effect of more than $max_multiline_modes modes " 477 "in channel $channel. Caused by client $client. Expect a desync.", 478 log_data_integer("max_multiline_modes", MAXMULTILINEMODES), 479 log_data_channel("channel", channel)); 480 break; 481 } 482 curr++; 483 m->modeline[curr] = safe_alloc(BUFSIZE); 484 m->paramline[curr] = safe_alloc(BUFSIZE); 485 m->numlines = curr+1; 486 what = 0; 487 } 488 if ((*(pvar[cnt]) == '+') && what != MODE_ADD) 489 { 490 strlcat_letter(m->modeline[curr], '+', BUFSIZE); 491 what = MODE_ADD; 492 } 493 if ((*(pvar[cnt]) == '-') && what != MODE_DEL) 494 { 495 strlcat_letter(m->modeline[curr], '-', BUFSIZE); 496 what = MODE_DEL; 497 } 498 strlcat_letter(m->modeline[curr], *(pvar[cnt] + 1), BUFSIZE); 499 strlcat(m->paramline[curr], &pvar[cnt][2], BUFSIZE); 500 strlcat_letter(m->paramline[curr], ' ', BUFSIZE); 501 } 502 503 for (i = 0; i <= curr; i++) 504 { 505 char *para_buf = m->paramline[i]; 506 /* Strip off useless space character (' ') at the end, if there is any */ 507 z = strlen(para_buf); 508 if ((z > 0) && (para_buf[z - 1] == ' ')) 509 para_buf[z - 1] = '\0'; 510 } 511 512 /* Now check for completely empty mode: */ 513 if ((curr == 0) && empty_mode(m->modeline[0])) 514 { 515 /* And convert it to a NULL result */ 516 safe_free_multilinemode(m); 517 return NULL; 518 } 519 520 return m; 521 } 522 523 const char *mode_ban_handler(Client *client, Channel *channel, const char *param, int what, int extbtype, Ban **banlist) 524 { 525 const char *tmpstr; 526 BanContext *b; 527 528 tmpstr = clean_ban_mask(param, what, client, 0); 529 if (BadPtr(tmpstr)) 530 { 531 /* Invalid ban. See if we can send an error about that (only for extbans) */ 532 if (MyUser(client) && is_extended_ban(param)) 533 { 534 const char *nextbanstr; 535 Extban *extban = findmod_by_bantype(param, &nextbanstr); 536 BanContext *b; 537 538 b = safe_alloc(sizeof(BanContext)); 539 b->client = client; 540 b->channel = channel; 541 b->banstr = nextbanstr; 542 b->is_ok_check = EXBCHK_PARAM; 543 b->what = what; 544 b->ban_type = extbtype; 545 if (extban && extban->is_ok) 546 extban->is_ok(b); 547 safe_free(b); 548 } 549 550 return NULL; 551 } 552 if (MyUser(client) && is_extended_ban(param)) 553 { 554 /* extban: check access if needed */ 555 const char *nextbanstr; 556 Extban *extban = findmod_by_bantype(tmpstr, &nextbanstr); 557 if (extban) 558 { 559 if ((extbtype == EXBTYPE_INVEX) && !(extban->options & EXTBOPT_INVEX)) 560 return NULL; /* this extended ban type does not support INVEX */ 561 if (extban->is_ok) 562 { 563 BanContext *b = safe_alloc(sizeof(BanContext)); 564 b->client = client; 565 b->channel = channel; 566 b->what = what; 567 b->ban_type = extbtype; 568 569 b->is_ok_check = EXBCHK_ACCESS; 570 b->banstr = nextbanstr; 571 if (!extban->is_ok(b)) 572 { 573 if (ValidatePermissionsForPath("channel:override:mode:extban",client,NULL,channel,NULL)) 574 { 575 /* TODO: send operoverride notice */ 576 } else { 577 b->banstr = nextbanstr; 578 b->is_ok_check = EXBCHK_ACCESS_ERR; 579 extban->is_ok(b); 580 safe_free(b); 581 return NULL; 582 } 583 } 584 b->banstr = nextbanstr; 585 b->is_ok_check = EXBCHK_PARAM; 586 if (!extban->is_ok(b)) 587 { 588 safe_free(b); 589 return NULL; 590 } 591 safe_free(b); 592 } 593 } 594 } 595 596 if ( (what == MODE_ADD && add_listmode(banlist, client, channel, tmpstr)) || 597 (what == MODE_DEL && del_listmode(banlist, channel, tmpstr))) 598 { 599 return NULL; /* already exists */ 600 } 601 602 return tmpstr; 603 } 604 605 /** Write the result of a mode change. 606 * This is used by do_mode_char_list_mode(), do_mode_char_member_mode() 607 * and do_extmode_char(). 608 * The result is later used by make_mode_str() to create the 609 * actual MODE line to be broadcasted to the channel and other servers. 610 */ 611 void do_mode_char_write(char pvar[MAXMODEPARAMS][MODEBUFLEN + 3], u_int *pcount, u_int what, char modeletter, const char *str) 612 { 613 /* Caller should have made sure there was room! */ 614 if (*pcount >= MAXMODEPARAMS) 615 #ifdef DEBUGMODE 616 abort(); 617 #else 618 return; 619 #endif 620 621 ircsnprintf(pvar[*pcount], MODEBUFLEN + 3, 622 "%c%c%s", 623 (what == MODE_ADD) ? '+' : '-', 624 modeletter, 625 str); 626 (*pcount)++; 627 } 628 629 int do_mode_char_list_mode(Channel *channel, long modetype, char modechar, const char *param, 630 u_int what, Client *client, 631 u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]) 632 { 633 const char *tmpstr; 634 635 /* Check if there is a parameter present */ 636 if (!param || *pcount >= MAXMODEPARAMS) 637 return 0; 638 639 switch (modetype) 640 { 641 case MODE_BAN: 642 if (!(tmpstr = mode_ban_handler(client, channel, param, what, EXBTYPE_BAN, &channel->banlist))) 643 break; /* rejected or duplicate */ 644 do_mode_char_write(pvar, pcount, what, modechar, tmpstr); 645 break; 646 case MODE_EXCEPT: 647 if (!(tmpstr = mode_ban_handler(client, channel, param, what, EXBTYPE_EXCEPT, &channel->exlist))) 648 break; /* rejected or duplicate */ 649 do_mode_char_write(pvar, pcount, what, modechar, tmpstr); 650 break; 651 case MODE_INVEX: 652 if (!(tmpstr = mode_ban_handler(client, channel, param, what, EXBTYPE_INVEX, &channel->invexlist))) 653 break; /* rejected or duplicate */ 654 do_mode_char_write(pvar, pcount, what, modechar, tmpstr); 655 break; 656 } 657 return 1; 658 } 659 660 /** Check access and if granted, set the extended chanmode to the requested value in memory. 661 * @returns amount of params eaten (0 or 1) 662 */ 663 int do_extmode_char(Channel *channel, Cmode *handler, const char *param, u_int what, 664 Client *client, u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]) 665 { 666 int paracnt = (what == MODE_ADD) ? handler->paracount : 0; 667 char mode = handler->letter; 668 int x; 669 const char *morphed; 670 671 if ((what == MODE_DEL) && handler->unset_with_param) 672 paracnt = 1; /* there's always an exception! */ 673 674 /* Expected a param and it isn't there? */ 675 if (paracnt && (!param || (*pcount >= MAXMODEPARAMS))) 676 return 0; 677 678 /* Prevent remote users from setting local channel modes */ 679 if (handler->local && !MyUser(client)) 680 return paracnt; 681 682 if (MyUser(client)) 683 { 684 x = handler->is_ok(client, channel, mode, param, EXCHK_ACCESS, what); 685 if ((x == EX_ALWAYS_DENY) || 686 ((x == EX_DENY) && !op_can_override("channel:override:mode:del",client,channel,handler) && !samode_in_progress)) 687 { 688 handler->is_ok(client, channel, mode, param, EXCHK_ACCESS_ERR, what); 689 return paracnt; /* Denied & error msg sent */ 690 } 691 if ((x == EX_DENY) && !samode_in_progress) 692 opermode = 1; /* override in progress... */ 693 } else { 694 /* remote user: we only need to check if we need to generate an operoverride msg */ 695 if (!IsULine(client) && IsUser(client) && op_can_override("channel:override:mode:del",client,channel,handler) && 696 (handler->is_ok(client, channel, mode, param, EXCHK_ACCESS, what) != EX_ALLOW)) 697 { 698 opermode = 1; /* override in progress... */ 699 } 700 } 701 702 if (handler->type == CMODE_MEMBER) 703 { 704 do_mode_char_member_mode_new(channel, handler, param, what, client, pcount, pvar); 705 return 1; 706 } 707 708 /* Check for multiple changes in 1 command (like +y-y+y 1 2, or +yy 1 2). */ 709 for (x = 0; x < *pcount; x++) 710 { 711 if (pvar[x][1] == handler->letter) 712 { 713 /* this is different than the old chanmode system, coz: 714 * "mode #chan +kkL #a #b #c" will get "+kL #a #b" which is wrong :p. 715 * we do eat the parameter. -- Syzop 716 */ 717 return paracnt; 718 } 719 } 720 721 /* w00t... a parameter mode */ 722 if (handler->paracount) 723 { 724 if (what == MODE_DEL) 725 { 726 if (!(channel->mode.mode & handler->mode)) 727 return paracnt; /* There's nothing to remove! */ 728 if (handler->unset_with_param) 729 { 730 /* Special extended channel mode requiring a parameter on unset. 731 * Any provided parameter is ok, the current one (that is set) will be used. 732 */ 733 do_mode_char_write(pvar, pcount, what, handler->letter, cm_getparameter(channel, handler->letter)); 734 } else { 735 /* Normal extended channel mode: deleting is just -X, no parameter. 736 * Nothing needs to be done here. 737 */ 738 } 739 } else { 740 /* add: is the parameter ok? */ 741 if (handler->is_ok(client, channel, mode, param, EXCHK_PARAM, what) == FALSE) 742 return paracnt; /* rejected by is_ok */ 743 744 morphed = handler->conv_param(param, client, channel); 745 if (!morphed) 746 return paracnt; /* rejected by conv_param */ 747 748 /* is it already set at the same value? if so, ignore it. */ 749 if (channel->mode.mode & handler->mode) 750 { 751 const char *now, *requested; 752 char flag = handler->letter; 753 now = cm_getparameter(channel, flag); 754 requested = handler->conv_param(param, client, channel); 755 if (now && requested && !strcmp(now, requested)) 756 return paracnt; /* ignore... */ 757 } 758 do_mode_char_write(pvar, pcount, what, handler->letter, handler->conv_param(param, client, channel)); 759 param = morphed; /* set param to converted parameter. */ 760 } 761 } 762 763 if (what == MODE_ADD) 764 { /* + */ 765 channel->mode.mode |= handler->mode; 766 if (handler->paracount) 767 cm_putparameter(channel, handler->letter, param); 768 RunHook(HOOKTYPE_MODECHAR_ADD, channel, (int)mode); 769 } else 770 { /* - */ 771 channel->mode.mode &= ~(handler->mode); 772 RunHook(HOOKTYPE_MODECHAR_DEL, channel, (int)mode); 773 if (handler->paracount) 774 cm_freeparameter(channel, handler->letter); 775 } 776 return paracnt; 777 } 778 779 /** Set or unset a mode on a member (eg +vhoaq/-vhoaq) */ 780 void do_mode_char_member_mode_new(Channel *channel, Cmode *handler, const char *param, u_int what, 781 Client *client, u_int *pcount, char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]) 782 { 783 Member *member = NULL; 784 Membership *membership = NULL; 785 Client *target; 786 int chasing = 0; 787 Hook *h; 788 char c[2]; 789 char modechar = handler->letter; 790 791 if (!(target = find_chasing(client, param, &chasing))) 792 return; 793 794 if (!target->user) 795 return; 796 797 if (!(membership = find_membership_link(target->user->channel, channel))) 798 { 799 sendnumeric(client, ERR_USERNOTINCHANNEL, target->name, channel->name); 800 return; 801 } 802 member = find_member_link(channel->members, target); 803 if (!member) 804 { 805 /* should never happen */ 806 unreal_log(ULOG_ERROR, "mode", "BUG_FIND_MEMBER_LINK_FAILED", target, 807 "[BUG] Client $target.details on channel $channel: " 808 "found via find_membership_link() but NOT found via find_member_link(). " 809 "This should never happen! Please report on https://bugs.unrealircd.org/", 810 log_data_client("target", target), 811 log_data_channel("channel", channel)); 812 return; 813 } 814 815 if ((what == MODE_ADD) && strchr(member->member_modes, modechar)) 816 return; /* already set */ 817 if ((what == MODE_DEL) && !strchr(member->member_modes, modechar)) 818 return; /* already unset */ 819 820 /* HOOKTYPE_MODE_DEOP code */ 821 if (what == MODE_DEL) 822 { 823 int ret = EX_ALLOW; 824 const char *badmode = NULL; 825 Hook *h; 826 const char *my_access; 827 Membership *my_membership; 828 829 /* Set "my_access" to access flags of the requestor */ 830 if (IsUser(client) && (my_membership = find_membership_link(client->user->channel, channel))) 831 my_access = my_membership->member_modes; /* client */ 832 else 833 my_access = ""; /* server */ 834 835 for (h = Hooks[HOOKTYPE_MODE_DEOP]; h; h = h->next) 836 { 837 int n = (*(h->func.intfunc))(client, target, channel, what, modechar, my_access, member->member_modes, &badmode); 838 if (n == EX_DENY) 839 { 840 ret = n; 841 } else 842 if (n == EX_ALWAYS_DENY) 843 { 844 ret = n; 845 break; 846 } 847 } 848 849 if (ret == EX_ALWAYS_DENY) 850 { 851 if (MyUser(client) && badmode) 852 sendto_one(client, NULL, "%s", badmode); /* send error message, if any */ 853 854 if (MyUser(client)) 855 return; /* stop processing this mode */ 856 } 857 858 /* This probably should work but is completely untested (the operoverride stuff, I mean): */ 859 if (ret == EX_DENY) 860 { 861 if (!op_can_override("channel:override:mode:del",client,channel,handler)) 862 { 863 if (badmode) 864 sendto_one(client, NULL, "%s", badmode); /* send error message, if any */ 865 return; /* stop processing this mode */ 866 } else { 867 opermode = 1; 868 } 869 } 870 } 871 872 if (what == MODE_ADD) 873 { 874 if (strchr(member->member_modes, modechar)) 875 return; /* already set */ 876 /* Set the mode */ 877 add_member_mode_fast(member, membership, modechar); 878 } else { 879 if (!strchr(member->member_modes, modechar)) 880 return; /* already unset */ 881 del_member_mode_fast(member, membership, modechar); 882 } 883 884 /* And write out the mode */ 885 do_mode_char_write(pvar, pcount, what, modechar, target->name); 886 } 887 888 /** In 2003 I introduced PROTOCTL CHANMODES= so remote servers (and services) 889 * could deal with unknown "parameter eating" channel modes, minimizing desyncs. 890 * Now, in 2015, I finally added the code to deal with this. -- Syzop 891 */ 892 int paracount_for_chanmode_from_server(Client *client, u_int what, char mode) 893 { 894 if (MyUser(client)) 895 return 0; /* no server, we have no idea, assume 0 paracount */ 896 897 if (!client->server) 898 { 899 /* If it's from a remote client then figure out from which "uplink" we 900 * received this MODE. The uplink is the directly-connected-server to us 901 * and may differ from the server the user is actually on. This is correct. 902 */ 903 if (!client->direction || !client->direction->server) 904 return 0; 905 client = client->direction; 906 } 907 908 if (client->server->features.chanmodes[0] && strchr(client->server->features.chanmodes[0], mode)) 909 return 1; /* 1 parameter for set, 1 parameter for unset */ 910 911 if (client->server->features.chanmodes[1] && strchr(client->server->features.chanmodes[1], mode)) 912 return 1; /* 1 parameter for set, 1 parameter for unset */ 913 914 if (client->server->features.chanmodes[2] && strchr(client->server->features.chanmodes[2], mode)) 915 return (what == MODE_ADD) ? 1 : 0; /* 1 parameter for set, no parameter for unset */ 916 917 if (client->server->features.chanmodes[3] && strchr(client->server->features.chanmodes[3], mode)) 918 return 0; /* no parameter for set, no parameter for unset */ 919 920 if (mode == '&') 921 return 0; /* & indicates bounce, it is not an actual mode character */ 922 923 if (mode == 'F') 924 return (what == MODE_ADD) ? 1 : 0; /* Future compatibility */ 925 926 /* If we end up here it means we have no idea if it is a parameter-eating or paramless 927 * channel mode. That's actually pretty bad. This shouldn't happen since CHANMODES= 928 * is sent since 2003 and the (often also required) EAUTH PROTOCTL is in there since 2010. 929 */ 930 unreal_log(ULOG_WARNING, "mode", "REMOTE_UNKNOWN_CHANNEL_MODE", client, 931 "Server $client sent us an unknown channel mode $what$mode_character!", 932 log_data_string("what", ((what == MODE_ADD) ? "+" : "-")), 933 log_data_char("mode_character", mode)); 934 935 return 0; 936 } 937 938 /** Quick way to find out parameter count for a channel mode. 939 * Only for LOCAL mode requests. For remote modes use 940 * paracount_for_chanmode_from_server() instead. 941 */ 942 int paracount_for_chanmode(u_int what, char mode) 943 { 944 if (me.server->features.chanmodes[0] && strchr(me.server->features.chanmodes[0], mode)) 945 return 1; /* 1 parameter for set, 1 parameter for unset */ 946 947 if (me.server->features.chanmodes[1] && strchr(me.server->features.chanmodes[1], mode)) 948 return 1; /* 1 parameter for set, 1 parameter for unset */ 949 950 if (me.server->features.chanmodes[2] && strchr(me.server->features.chanmodes[2], mode)) 951 return (what == MODE_ADD) ? 1 : 0; /* 1 parameter for set, no parameter for unset */ 952 953 if (me.server->features.chanmodes[3] && strchr(me.server->features.chanmodes[3], mode)) 954 return 0; /* no parameter for set, no parameter for unset */ 955 956 /* Not found: */ 957 return 0; 958 } 959 960 MultiLineMode *_set_mode(Channel *channel, Client *client, int parc, const char *parv[], u_int *pcount, 961 char pvar[MAXMODEPARAMS][MODEBUFLEN + 3]) 962 { 963 Cmode *cm = NULL; 964 MultiLineMode *mlm = NULL; 965 const char *curchr; 966 const char *argument; 967 char argumentbuf[MODEBUFLEN+1]; 968 u_int what = MODE_ADD; 969 long modetype = 0; 970 int paracount = 1; 971 #ifdef DEVELOP 972 char *tmpo = NULL; 973 #endif 974 CoreChannelModeTable *tab = &corechannelmodetable[0]; 975 CoreChannelModeTable foundat; 976 int found = 0; 977 int sent_mlock_warning = 0; 978 int checkrestr = 0, warnrestr = 1; 979 Cmode_t oldem; 980 paracount = 1; 981 *pcount = 0; 982 983 oldem = channel->mode.mode; 984 if (RESTRICT_CHANNELMODES && !ValidatePermissionsForPath("immune:restrict-channelmodes",client,NULL,channel,NULL)) /* "cache" this */ 985 checkrestr = 1; 986 987 for (curchr = parv[0]; *curchr; curchr++) 988 { 989 switch (*curchr) 990 { 991 case '+': 992 what = MODE_ADD; 993 break; 994 case '-': 995 what = MODE_DEL; 996 break; 997 default: 998 if (MyUser(client) && channel->mode_lock && strchr(channel->mode_lock, *curchr) != NULL) 999 { 1000 if (!IsOper(client) || find_server(SERVICES_NAME, NULL) || 1001 !ValidatePermissionsForPath("channel:override:mlock",client,NULL,channel,NULL)) 1002 { 1003 if (!sent_mlock_warning) 1004 { 1005 sendnumeric(client, ERR_MLOCKRESTRICTED, channel->name, *curchr, channel->mode_lock); 1006 sent_mlock_warning++; 1007 } 1008 continue; 1009 } 1010 } 1011 found = 0; 1012 tab = &corechannelmodetable[0]; 1013 while ((tab->mode != 0x0) && found == 0) 1014 { 1015 if (tab->flag == *curchr) 1016 { 1017 found = 1; 1018 foundat = *tab; 1019 } 1020 tab++; 1021 } 1022 if (found == 1) 1023 { 1024 modetype = foundat.mode; 1025 } else { 1026 /* Maybe in extmodes */ 1027 for (cm=channelmodes; cm; cm = cm->next) 1028 { 1029 if (cm->letter == *curchr) 1030 { 1031 found = 2; 1032 break; 1033 } 1034 } 1035 } 1036 if (found == 0) /* Mode char unknown */ 1037 { 1038 if (!MyUser(client)) 1039 paracount += paracount_for_chanmode_from_server(client, what, *curchr); 1040 else 1041 sendnumeric(client, ERR_UNKNOWNMODE, *curchr); 1042 break; 1043 } 1044 1045 if (checkrestr && strchr(RESTRICT_CHANNELMODES, *curchr)) 1046 { 1047 if (warnrestr) 1048 { 1049 sendnotice(client, "Setting/removing of channelmode(s) '%s' has been disabled.", 1050 RESTRICT_CHANNELMODES); 1051 warnrestr = 0; 1052 } 1053 paracount += paracount_for_chanmode(what, *curchr); 1054 break; 1055 } 1056 1057 if ((paracount < parc) && parv[paracount]) 1058 { 1059 strlcpy(argumentbuf, parv[paracount], sizeof(argumentbuf)); 1060 argument = argumentbuf; 1061 } else { 1062 argument = NULL; 1063 } 1064 1065 if (found == 1) 1066 paracount += do_mode_char_list_mode(channel, modetype, *curchr, argument, what, client, pcount, pvar); 1067 else if (found == 2) 1068 paracount += do_extmode_char(channel, cm, argument, what, client, pcount, pvar); 1069 break; 1070 } /* switch(*curchr) */ 1071 } /* for loop through mode letters */ 1072 1073 mlm = make_mode_str(client, channel, oldem, *pcount, pvar); 1074 return mlm; 1075 } 1076 1077 /* 1078 * cmd_umode() added 15/10/91 By Darren Reed. 1079 * parv[1] - username to change mode for 1080 * parv[2] - modes to change 1081 */ 1082 CMD_FUNC(_cmd_umode) 1083 { 1084 Umode *um; 1085 const char *m; 1086 Client *acptr; 1087 int what; 1088 long oldumodes = 0; 1089 char oldsnomask[64]; 1090 /* (small note: keep 'what' as an int. -- Syzop). */ 1091 short rpterror = 0, umode_restrict_err = 0, chk_restrict = 0, modex_err = 0; 1092 1093 what = MODE_ADD; 1094 *oldsnomask = '\0'; 1095 1096 if (parc < 2) 1097 { 1098 sendnumeric(client, ERR_NEEDMOREPARAMS, "MODE"); 1099 return; 1100 } 1101 1102 if (!(acptr = find_user(parv[1], NULL))) 1103 { 1104 if (MyConnect(client)) 1105 { 1106 sendnumeric(client, ERR_NOSUCHNICK, parv[1]); 1107 } 1108 return; 1109 } 1110 if (acptr != client) 1111 { 1112 sendnumeric(client, ERR_USERSDONTMATCH); 1113 return; 1114 } 1115 1116 if (parc < 3) 1117 { 1118 sendnumeric(client, RPL_UMODEIS, get_usermode_string(client)); 1119 if (client->user->snomask) 1120 sendnumeric(client, RPL_SNOMASK, client->user->snomask); 1121 return; 1122 } 1123 1124 userhost_save_current(client); /* save host, in case we do any +x/-x or similar */ 1125 1126 oldumodes = client->umodes; 1127 1128 if (RESTRICT_USERMODES && MyUser(client) && !ValidatePermissionsForPath("immune:restrict-usermodes",client,NULL,NULL,NULL)) 1129 chk_restrict = 1; 1130 1131 if (client->user->snomask) 1132 strlcpy(oldsnomask, client->user->snomask, sizeof(oldsnomask)); 1133 1134 /* 1135 * parse mode change string(s) 1136 */ 1137 for (m = parv[2]; *m; m++) 1138 { 1139 if (chk_restrict && strchr(RESTRICT_USERMODES, *m)) 1140 { 1141 if (!umode_restrict_err) 1142 { 1143 sendnotice(client, "Setting/removing of usermode(s) '%s' has been disabled.", 1144 RESTRICT_USERMODES); 1145 umode_restrict_err = 1; 1146 } 1147 continue; 1148 } 1149 switch (*m) 1150 { 1151 case '+': 1152 what = MODE_ADD; 1153 break; 1154 case '-': 1155 what = MODE_DEL; 1156 break; 1157 /* we may not get these, 1158 * but they shouldnt be in default 1159 */ 1160 case ' ': 1161 case '\t': 1162 break; 1163 case 's': 1164 if (what == MODE_DEL) 1165 { 1166 if (parc >= 4 && client->user->snomask) 1167 { 1168 set_snomask(client, parv[3]); 1169 if (client->user->snomask == NULL) 1170 goto def; 1171 break; 1172 } else { 1173 set_snomask(client, NULL); 1174 goto def; 1175 } 1176 } 1177 if ((what == MODE_ADD) && IsOper(client)) 1178 { 1179 if (parc < 4) 1180 set_snomask(client, OPER_SNOMASKS); 1181 else 1182 set_snomask(client, parv[3]); 1183 goto def; 1184 } 1185 break; 1186 case 'o': 1187 case 'O': 1188 if (IsQuarantined(client->direction)) 1189 { 1190 unreal_log(ULOG_INFO, "mode", "OPER_KILLED_QUARANTINE", client, 1191 "QUARANTINE: Oper $client.details on server $client.user.servername killed, due to quarantine"); 1192 sendto_server(NULL, 0, 0, NULL, ":%s KILL %s :Quarantined: no oper privileges allowed", me.id, client->name); 1193 exit_client(client, NULL, "Quarantined: no oper privileges allowed"); 1194 return; 1195 } 1196 /* A local user trying to set himself +o/+O is denied here. 1197 * A while later (outside this loop) it is handled as well (and +C, +N, etc too) 1198 * but we need to take care here too because it might cause problems 1199 * that's just asking for bugs! -- Syzop. 1200 */ 1201 if (MyUser(client) && (what == MODE_ADD)) /* Someone setting himself +o? Deny it. */ 1202 break; 1203 goto def; 1204 case 't': 1205 case 'x': 1206 /* set::anti-flood::vhost-flood */ 1207 if (MyUser(client)) 1208 { 1209 if ((what == MODE_DEL) && !ValidatePermissionsForPath("immune:vhost-flood",client,NULL,NULL,NULL) && 1210 flood_limit_exceeded(client, FLD_VHOST)) 1211 { 1212 /* Throttle... */ 1213 if (!modex_err) 1214 { 1215 sendnotice(client, "*** Setting -%c too fast. Please try again later.", *m); 1216 modex_err = 1; 1217 } 1218 break; 1219 } 1220 } 1221 1222 switch (UHOST_ALLOWED) 1223 { 1224 case UHALLOW_ALWAYS: 1225 goto def; 1226 case UHALLOW_NEVER: 1227 if (MyUser(client)) 1228 { 1229 if (!modex_err) 1230 { 1231 sendnotice(client, "*** Setting %c%c is disabled", 1232 what == MODE_ADD ? '+' : '-', *m); 1233 modex_err = 1; 1234 } 1235 break; 1236 } 1237 goto def; 1238 case UHALLOW_NOCHANS: 1239 if (MyUser(client) && client->user->joined) 1240 { 1241 if (!modex_err) 1242 { 1243 sendnotice(client, "*** Setting %c%c can not be done while you are on channels", 1244 what == MODE_ADD ? '+' : '-', *m); 1245 modex_err = 1; 1246 } 1247 break; 1248 } 1249 goto def; 1250 case UHALLOW_REJOIN: 1251 /* Handled later */ 1252 goto def; 1253 } 1254 break; 1255 default: 1256 def: 1257 for (um = usermodes; um; um = um->next) 1258 { 1259 if (um->letter == *m) 1260 { 1261 if (um->allowed && !um->allowed(client,what)) 1262 break; 1263 if (what == MODE_ADD) 1264 client->umodes |= um->mode; 1265 else 1266 client->umodes &= ~um->mode; 1267 break; 1268 } 1269 } 1270 if (!um && MyConnect(client) && !rpterror) 1271 { 1272 sendnumeric(client, ERR_UMODEUNKNOWNFLAG); 1273 rpterror = 1; 1274 } 1275 break; 1276 } /* switch */ 1277 } /* for */ 1278 1279 /* Don't let non-ircops set ircop-only modes or snomasks */ 1280 if (!ValidatePermissionsForPath("self:opermodes",client,NULL,NULL,NULL)) 1281 { 1282 if ((oldumodes & UMODE_OPER) && IsOper(client)) 1283 { 1284 /* User is an oper but does not have the self:opermodes capability. 1285 * This only happens for heavily restricted IRCOps. 1286 * Fixes bug https://bugs.unrealircd.org/view.php?id=5130 1287 */ 1288 int i; 1289 1290 /* MODES */ 1291 for (um = usermodes; um; um = um->next) 1292 { 1293 if (um->unset_on_deoper) 1294 { 1295 /* This is an oper mode. Is it set now and wasn't earlier? 1296 * then it needs to be stripped, as setting it is not 1297 * permitted. 1298 */ 1299 if ((client->umodes & um->mode) && !(oldumodes & um->mode)) 1300 client->umodes &= ~um->mode; /* remove */ 1301 } 1302 } 1303 1304 /* SNOMASKS: user can delete existing but not add new ones */ 1305 if (client->user->snomask) 1306 { 1307 char rerun; 1308 do { 1309 char *p; 1310 1311 rerun = 0; 1312 for (p = client->user->snomask; *p; p++) 1313 { 1314 if (!strchr(oldsnomask, *p)) 1315 { 1316 /* It is set now, but was not earlier? 1317 * Then it needs to be stripped, as setting is not permitted. 1318 * And re-run the loop 1319 */ 1320 delletterfromstring(client->user->snomask, *p); 1321 rerun = 1; 1322 break; 1323 } 1324 } 1325 } while(rerun); 1326 /* And make sure an empty snomask ("") becomes a NULL pointer */ 1327 if (client->user->snomask && !*client->user->snomask) 1328 remove_all_snomasks(client); 1329 } 1330 } else { 1331 /* User isn't an ircop at all. The solution is simple: */ 1332 remove_oper_privileges(client, 0); 1333 } 1334 } 1335 1336 if (MyUser(client) && (client->umodes & UMODE_SECURE) && !IsSecure(client)) 1337 client->umodes &= ~UMODE_SECURE; 1338 1339 /* -x translates to -xt (if applicable) */ 1340 if ((oldumodes & UMODE_HIDE) && !IsHidden(client)) 1341 client->umodes &= ~UMODE_SETHOST; 1342 1343 /* Vhost unset = unset some other data as well */ 1344 if ((oldumodes & UMODE_SETHOST) && !IsSetHost(client)) 1345 { 1346 swhois_delete(client, "vhost", "*", &me, NULL); 1347 } 1348 1349 /* +x or -t+x */ 1350 if ((IsHidden(client) && !(oldumodes & UMODE_HIDE)) || 1351 ((oldumodes & UMODE_SETHOST) && !IsSetHost(client) && IsHidden(client))) 1352 { 1353 if (!dontspread) 1354 sendto_server(client, PROTO_VHP, 0, NULL, ":%s SETHOST :%s", 1355 client->name, client->user->virthost); 1356 1357 /* Set the vhost */ 1358 safe_strdup(client->user->virthost, client->user->cloakedhost); 1359 1360 /* Notify */ 1361 userhost_changed(client); 1362 } 1363 1364 /* -x */ 1365 if (!IsHidden(client) && (oldumodes & UMODE_HIDE)) 1366 { 1367 /* (Re)create the cloaked virthost, because it will be used 1368 * for ban-checking... free+recreate here because it could have 1369 * been a vhost for example. -- Syzop 1370 */ 1371 safe_strdup(client->user->virthost, client->user->cloakedhost); 1372 1373 /* Notify */ 1374 userhost_changed(client); 1375 } 1376 /* 1377 * If I understand what this code is doing correctly... 1378 * If the user WAS an operator and has now set themselves -o/-O 1379 * then remove their access, d'oh! 1380 * In order to allow opers to do stuff like go +o, +h, -o and 1381 * remain +h, I moved this code below those checks. It should be 1382 * O.K. The above code just does normal access flag checks. This 1383 * only changes the operflag access level. -Cabal95 1384 */ 1385 if ((oldumodes & UMODE_OPER) && !IsOper(client) && MyConnect(client)) 1386 { 1387 list_del(&client->special_node); 1388 if (MyUser(client)) 1389 RunHook(HOOKTYPE_LOCAL_OPER, client, 0, NULL, NULL); 1390 remove_oper_privileges(client, 0); 1391 } 1392 1393 if (!(oldumodes & UMODE_OPER) && IsOper(client)) 1394 irccounts.operators++; 1395 1396 /* deal with opercounts and stuff */ 1397 if ((oldumodes & UMODE_OPER) && !IsOper(client)) 1398 { 1399 irccounts.operators--; 1400 VERIFY_OPERCOUNT(client, "umode1"); 1401 } else /* YES this 'else' must be here, otherwise we can decrease twice. fixes opercount bug. */ 1402 if (!(oldumodes & UMODE_HIDEOPER) && IsHideOper(client)) 1403 { 1404 irccounts.operators--; 1405 VERIFY_OPERCOUNT(client, "umode2"); 1406 } 1407 /* end of dealing with opercounts */ 1408 1409 if ((oldumodes & UMODE_HIDEOPER) && !IsHideOper(client)) 1410 { 1411 irccounts.operators++; 1412 } 1413 if (!(oldumodes & UMODE_INVISIBLE) && IsInvisible(client)) 1414 irccounts.invisible++; 1415 if ((oldumodes & UMODE_INVISIBLE) && !IsInvisible(client)) 1416 irccounts.invisible--; 1417 1418 if (MyConnect(client) && !IsOper(client)) 1419 remove_oper_privileges(client, 0); 1420 1421 /* 1422 * compare new flags with old flags and send string which 1423 * will cause servers to update correctly. 1424 */ 1425 if (oldumodes != client->umodes) 1426 RunHook(HOOKTYPE_UMODE_CHANGE, client, oldumodes, client->umodes); 1427 if (dontspread == 0) 1428 send_umode_out(client, 1, oldumodes); 1429 1430 if (MyConnect(client) && client->user->snomask && strcmp(oldsnomask, client->user->snomask)) 1431 sendnumeric(client, RPL_SNOMASK, client->user->snomask); 1432 } 1433 1434 CMD_FUNC(cmd_mlock) 1435 { 1436 Channel *channel = NULL; 1437 time_t t; 1438 1439 if ((parc < 3) || BadPtr(parv[2])) 1440 return; 1441 1442 t = (time_t) atol(parv[1]); 1443 1444 /* Now, try to find the channel in question */ 1445 channel = find_channel(parv[2]); 1446 if (!channel) 1447 return; 1448 1449 /* Senders' Channel t is higher, drop it. */ 1450 if (t > channel->creationtime) 1451 return; 1452 1453 if (IsServer(client)) 1454 set_channel_mlock(client, channel, parv[3], TRUE); 1455 } 1456 1457 void mode_operoverride_msg(Client *client, Channel *channel, char *modebuf, char *parabuf) 1458 { 1459 char buf[1024]; 1460 1461 if (empty_mode(modebuf)) 1462 return; 1463 1464 /* Internally we have this distinction between modebuf and parabuf, 1465 * but this makes little sense to maintain in JSON. 1466 */ 1467 snprintf(buf, sizeof(buf), "%s %s", modebuf, parabuf); 1468 1469 unreal_log(ULOG_INFO, "operoverride", "OPEROVERRIDE_MODE", client, 1470 "OperOverride: $client.details changed channel mode of $channel to: $channel_mode", 1471 log_data_string("override_type", "mode"), 1472 log_data_string("channel_mode", buf), 1473 log_data_channel("channel", channel)); 1474 } 1475 1476 /* Deal with information requests from local users, such as: 1477 * MODE #chan b Show the ban list 1478 * MODE #chan e Show the ban exemption list 1479 * MODE #chan I Show the invite exception list 1480 * MODE #chan q Show list of channel owners 1481 * MODE #chan a Show list of channel admins 1482 * @returns 1 if processed as a mode list (please return), 1483 * 0 if not (continue with the MODE as it likely is a set request). 1484 */ 1485 int list_mode_request(Client *client, Channel *channel, const char *req) 1486 { 1487 const char *p; 1488 Ban *ban; 1489 Member *member; 1490 1491 for (p = req; *p; p++) 1492 if (strchr("beIqa", *p)) 1493 break; 1494 1495 if (!*p) 1496 return 0; /* not handled, proceed with the MODE set attempt */ 1497 1498 /* First, check access */ 1499 if (strchr("beI", *p)) 1500 { 1501 if (!IsMember(client, channel) && !ValidatePermissionsForPath("channel:see:mode:remotebanlist",client,NULL,channel,NULL)) 1502 { 1503 sendnumeric(client, ERR_NOTONCHANNEL, channel->name); 1504 return 1; /* handled */ 1505 } 1506 } else { 1507 if (!IsMember(client, channel) && !ValidatePermissionsForPath("channel:see:mode:remoteownerlist",client,NULL,channel,NULL)) 1508 { 1509 sendnumeric(client, ERR_NOTONCHANNEL, channel->name); 1510 return 1; /* handled */ 1511 } 1512 } 1513 1514 switch(*p) 1515 { 1516 case 'b': 1517 for (ban = channel->banlist; ban; ban = ban->next) 1518 sendnumeric(client, RPL_BANLIST, channel->name, ban->banstr, ban->who, (long long)ban->when); 1519 sendnumeric(client, RPL_ENDOFBANLIST, channel->name); 1520 break; 1521 case 'e': 1522 for (ban = channel->exlist; ban; ban = ban->next) 1523 sendnumeric(client, RPL_EXLIST, channel->name, ban->banstr, ban->who, (long long)ban->when); 1524 sendnumeric(client, RPL_ENDOFEXLIST, channel->name); 1525 break; 1526 case 'I': 1527 for (ban = channel->invexlist; ban; ban = ban->next) 1528 sendnumeric(client, RPL_INVEXLIST, channel->name, ban->banstr, ban->who, (long long)ban->when); 1529 sendnumeric(client, RPL_ENDOFINVEXLIST, channel->name); 1530 break; 1531 case 'q': 1532 for (member = channel->members; member; member = member->next) 1533 if (strchr(member->member_modes, 'q')) 1534 sendnumeric(client, RPL_QLIST, channel->name, member->client->name); 1535 sendnumeric(client, RPL_ENDOFQLIST, channel->name); 1536 break; 1537 case 'a': 1538 for (member = channel->members; member; member = member->next) 1539 if (strchr(member->member_modes, 'a')) 1540 sendnumeric(client, RPL_ALIST, channel->name, member->client->name); 1541 sendnumeric(client, RPL_ENDOFALIST, channel->name); 1542 break; 1543 } 1544 1545 return 1; /* handled */ 1546 } 1547 1548 void _set_channel_mode(Channel *channel, MessageTag *mtags, const char *modes, const char *parameters) 1549 { 1550 char buf[512]; 1551 char *p, *param; 1552 int myparc = 1, i; 1553 char *myparv[512]; 1554 1555 memset(&myparv, 0, sizeof(myparv)); 1556 myparv[0] = raw_strdup(modes); 1557 1558 strlcpy(buf, parameters, sizeof(buf)); 1559 for (param = strtoken(&p, buf, " "); param; param = strtoken(&p, NULL, " ")) 1560 myparv[myparc++] = raw_strdup(param); 1561 myparv[myparc] = NULL; 1562 1563 SetULine(&me); // hack for crash.. set ulined so no access checks. 1564 do_mode(channel, &me, mtags, myparc, (const char **)myparv, 0, 0); 1565 ClearULine(&me); // and clear it again.. 1566 1567 for (i = 0; i < myparc; i++) 1568 safe_free(myparv[i]); 1569 }