unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
md.c (15443B)
1 /* 2 * Module Data module (command MD) 3 * (C) Copyright 2014-.. Bram Matthys and The UnrealIRCd Team 4 * 5 * This file contains all commands that deal with sending and 6 * receiving module data over the network. 7 */ 8 9 #include "unrealircd.h" 10 11 ModuleHeader MOD_HEADER 12 = { 13 "md", 14 "5.0", 15 "command /MD (S2S only)", 16 "UnrealIRCd Team", 17 "unrealircd-6", 18 }; 19 20 CMD_FUNC(cmd_md); 21 void _broadcast_md_client(ModDataInfo *mdi, Client *client, ModData *md); 22 void _broadcast_md_channel(ModDataInfo *mdi, Channel *channel, ModData *md); 23 void _broadcast_md_member(ModDataInfo *mdi, Channel *channel, Member *m, ModData *md); 24 void _broadcast_md_membership(ModDataInfo *mdi, Client *client, Membership *m, ModData *md); 25 void _broadcast_md_globalvar(ModDataInfo *mdi, ModData *md); 26 void _broadcast_md_client_cmd(Client *except, Client *sender, Client *client, const char *varname, const char *value); 27 void _broadcast_md_channel_cmd(Client *except, Client *sender, Channel *channel, const char *varname, const char *value); 28 void _broadcast_md_member_cmd(Client *except, Client *sender, Channel *channel, Client *client, const char *varname, const char *value); 29 void _broadcast_md_membership_cmd(Client *except, Client *sender, Client *client, Channel *channel, const char *varname, const char *value); 30 void _broadcast_md_globalvar_cmd(Client *except, Client *sender, const char *varname, const char *value); 31 void _moddata_add_s2s_mtags(Client *client, MessageTag **mtags); 32 void _moddata_extract_s2s_mtags(Client *client, MessageTag *mtags); 33 void _send_moddata_client(Client *srv, Client *client); 34 void _send_moddata_channel(Client *srv, Channel *channel); 35 void _send_moddata_members(Client *srv); 36 void _broadcast_moddata_client(Client *client); 37 38 extern MODVAR ModDataInfo *MDInfo; 39 40 MOD_TEST() 41 { 42 MARK_AS_OFFICIAL_MODULE(modinfo); 43 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_CLIENT, _broadcast_md_client); 44 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_CHANNEL, _broadcast_md_channel); 45 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_MEMBER, _broadcast_md_member); 46 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_MEMBERSHIP, _broadcast_md_membership); 47 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_GLOBALVAR, _broadcast_md_globalvar); 48 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_CLIENT_CMD, _broadcast_md_client_cmd); 49 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_CHANNEL_CMD, _broadcast_md_channel_cmd); 50 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_MEMBER_CMD, _broadcast_md_member_cmd); 51 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_MEMBERSHIP_CMD, _broadcast_md_membership_cmd); 52 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MD_GLOBALVAR_CMD, _broadcast_md_globalvar_cmd); 53 EfunctionAddVoid(modinfo->handle, EFUNC_MODDATA_ADD_S2S_MTAGS, _moddata_add_s2s_mtags); 54 EfunctionAddVoid(modinfo->handle, EFUNC_MODDATA_EXTRACT_S2S_MTAGS, _moddata_extract_s2s_mtags); 55 EfunctionAddVoid(modinfo->handle, EFUNC_SEND_MODDATA_CLIENT, _send_moddata_client); 56 EfunctionAddVoid(modinfo->handle, EFUNC_SEND_MODDATA_CHANNEL, _send_moddata_channel); 57 EfunctionAddVoid(modinfo->handle, EFUNC_SEND_MODDATA_MEMBERS, _send_moddata_members); 58 EfunctionAddVoid(modinfo->handle, EFUNC_BROADCAST_MODDATA_CLIENT, _broadcast_moddata_client); 59 return MOD_SUCCESS; 60 } 61 62 MOD_INIT() 63 { 64 CommandAdd(modinfo->handle, "MD", cmd_md, MAXPARA, CMD_SERVER); 65 return MOD_SUCCESS; 66 } 67 68 MOD_LOAD() 69 { 70 return MOD_SUCCESS; 71 } 72 73 74 MOD_UNLOAD() 75 { 76 return MOD_SUCCESS; 77 } 78 79 /** Check if client may write to this MD object */ 80 int md_access_check(Client *client, ModDataInfo *md, Client *target) 81 { 82 if ((client == target) && md->self_write) 83 return 1; 84 85 if (MyConnect(target) && !md->remote_write) 86 { 87 unreal_log(ULOG_WARNING, "md", "REMOTE_MD_WRITE_DENIED", client, 88 "Remote server $client tried to write moddata $moddata_name " 89 "of a client from ours ($target.name) -- attempt BLOCKED", 90 log_data_string("moddata_name", md->name), 91 log_data_client("target", target)); 92 return 0; 93 } 94 95 return 1; 96 } 97 98 /** Set ModData command. 99 * Syntax: MD <type> <object name> <variable name> <value> 100 * Example: MD client Syzop sslfp 123456789 101 * 102 * If <value> is ommitted, the variable is unset & freed. 103 * 104 * The appropriate module is called to set the data (unserialize) and 105 * then the command is broadcasted to all other servers. 106 * 107 * Technical documentation (if writing services) is available at: 108 * https://www.unrealircd.org/docs/Server_protocol:MD_command 109 * Module API documentation (if writing an UnrealIRCd module): 110 * https://www.unrealircd.org/docs/Dev:Module_Storage 111 */ 112 CMD_FUNC(cmd_md) 113 { 114 const char *type, *objname, *varname, *value; 115 ModDataInfo *md; 116 117 if (!IsServer(client) || (parc < 4) || BadPtr(parv[3])) 118 return; 119 120 type = parv[1]; 121 objname = parv[2]; 122 varname = parv[3]; 123 value = parv[4]; /* may be NULL */ 124 125 if (!strcmp(type, "client")) 126 { 127 Client *target = find_client(objname, NULL); 128 md = findmoddata_byname(varname, MODDATATYPE_CLIENT); 129 if (!md || !md->unserialize || !target) 130 return; 131 132 if (!md_access_check(client, md, target)) 133 return; 134 135 if (value) 136 md->unserialize(value, &moddata_client(target, md)); 137 else 138 { 139 if (md->free) 140 md->free(&moddata_client(target, md)); 141 memset(&moddata_client(target, md), 0, sizeof(ModData)); 142 } 143 /* Pass on to other servers */ 144 broadcast_md_client_cmd(client->direction, client, target, varname, value); 145 } else 146 if (!strcmp(type, "channel")) 147 { 148 Channel *channel = find_channel(objname); 149 md = findmoddata_byname(varname, MODDATATYPE_CHANNEL); 150 if (!md || !md->unserialize || !channel) 151 return; 152 if (value) 153 md->unserialize(value, &moddata_channel(channel, md)); 154 else 155 { 156 if (md->free) 157 md->free(&moddata_channel(channel, md)); 158 memset(&moddata_channel(channel, md), 0, sizeof(ModData)); 159 } 160 /* Pass on to other servers */ 161 broadcast_md_channel_cmd(client->direction, client, channel, varname, value); 162 } else 163 if (!strcmp(type, "member")) 164 { 165 Client *target; 166 Channel *channel; 167 Member *m; 168 char *p; 169 170 /* for member the object name is like '#channel/Syzop' */ 171 p = strchr(objname, ':'); 172 if (!p) 173 return; 174 *p++ = '\0'; 175 176 channel = find_channel(objname); 177 if (!channel) 178 return; 179 180 target = find_user(p, NULL); 181 if (!target) 182 return; 183 184 m = find_member_link(channel->members, target); 185 if (!m) 186 return; 187 188 md = findmoddata_byname(varname, MODDATATYPE_MEMBER); 189 if (!md || !md->unserialize) 190 return; 191 192 if (!md_access_check(client, md, target)) 193 return; 194 195 if (value) 196 md->unserialize(value, &moddata_member(m, md)); 197 else 198 { 199 if (md->free) 200 md->free(&moddata_member(m, md)); 201 memset(&moddata_member(m, md), 0, sizeof(ModData)); 202 } 203 /* Pass on to other servers */ 204 broadcast_md_member_cmd(client->direction, client, channel, target, varname, value); 205 } else 206 if (!strcmp(type, "membership")) 207 { 208 Client *target; 209 Channel *channel; 210 Membership *m; 211 char *p; 212 213 /* for membership the object name is like 'Syzop/#channel' */ 214 p = strchr(objname, ':'); 215 if (!p) 216 return; 217 *p++ = '\0'; 218 219 target = find_user(objname, NULL); 220 if (!target) 221 return; 222 223 channel = find_channel(p); 224 if (!channel) 225 return; 226 227 m = find_membership_link(target->user->channel, channel); 228 if (!m) 229 return; 230 231 md = findmoddata_byname(varname, MODDATATYPE_MEMBERSHIP); 232 if (!md || !md->unserialize) 233 return; 234 235 if (!md_access_check(client, md, target)) 236 return; 237 238 if (value) 239 md->unserialize(value, &moddata_membership(m, md)); 240 else 241 { 242 if (md->free) 243 md->free(&moddata_membership(m, md)); 244 memset(&moddata_membership(m, md), 0, sizeof(ModData)); 245 } 246 /* Pass on to other servers */ 247 broadcast_md_membership_cmd(client->direction, client, target, channel, varname, value); 248 } else 249 if (!strcmp(type, "globalvar")) 250 { 251 /* objname is ignored */ 252 md = findmoddata_byname(varname, MODDATATYPE_GLOBAL_VARIABLE); 253 if (!md || !md->unserialize) 254 return; 255 if (value) 256 md->unserialize(value, &moddata_global_variable(md)); 257 else 258 { 259 if (md->free) 260 md->free(&moddata_global_variable(md)); 261 memset(&moddata_global_variable(md), 0, sizeof(ModData)); 262 } 263 /* Pass on to other servers */ 264 broadcast_md_globalvar_cmd(client->direction, client, varname, value); 265 } 266 } 267 268 void _broadcast_md_client_cmd(Client *except, Client *sender, Client *client, const char *varname, const char *value) 269 { 270 if (value) 271 { 272 sendto_server(except, 0, 0, NULL, ":%s MD %s %s %s :%s", 273 sender->id, "client", client->id, varname, value); 274 } 275 else 276 { 277 sendto_server(except, 0, 0, NULL, ":%s MD %s %s %s", 278 sender->id, "client", client->id, varname); 279 } 280 } 281 282 void _broadcast_md_channel_cmd(Client *except, Client *sender, Channel *channel, const char *varname, const char *value) 283 { 284 if (value) 285 sendto_server(except, 0, 0, NULL, ":%s MD %s %s %s :%s", 286 sender->id, "channel", channel->name, varname, value); 287 else 288 sendto_server(except, 0, 0, NULL, ":%s MD %s %s %s", 289 sender->id, "channel", channel->name, varname); 290 } 291 292 void _broadcast_md_member_cmd(Client *except, Client *sender, Channel *channel, Client *client, const char *varname, const char *value) 293 { 294 if (value) 295 { 296 sendto_server(except, 0, 0, NULL, ":%s MD %s %s:%s %s :%s", 297 sender->id, "member", channel->name, client->id, varname, value); 298 } 299 else 300 { 301 sendto_server(except, 0, 0, NULL, ":%s MD %s %s:%s %s", 302 sender->id, "member", channel->name, client->id, varname); 303 } 304 } 305 306 void _broadcast_md_membership_cmd(Client *except, Client *sender, Client *client, Channel *channel, const char *varname, const char *value) 307 { 308 if (value) 309 { 310 sendto_server(except, 0, 0, NULL, ":%s MD %s %s:%s %s :%s", 311 sender->id, "membership", client->id, channel->name, varname, value); 312 } 313 else 314 { 315 sendto_server(except, 0, 0, NULL, ":%s MD %s %s:%s %s", 316 sender->id, "membership", client->id, channel->name, varname); 317 } 318 } 319 320 void _broadcast_md_globalvar_cmd(Client *except, Client *sender, const char *varname, const char *value) 321 { 322 if (value) 323 { 324 sendto_server(except, 0, 0, NULL, ":%s MD %s %s :%s", 325 sender->id, "globalvar", varname, value); 326 } 327 else 328 { 329 sendto_server(except, 0, 0, NULL, ":%s MD %s %s", 330 sender->id, "globalvar", varname); 331 } 332 } 333 334 /** Send module data update to all servers. 335 * @param mdi Module Data Info structure (which you received from ModDataAdd) 336 * @param client The affected client 337 * @param md The ModData. May be NULL for unset. 338 */ 339 340 void _broadcast_md_client(ModDataInfo *mdi, Client *client, ModData *md) 341 { 342 const char *value = md ? mdi->serialize(md) : NULL; 343 344 broadcast_md_client_cmd(NULL, &me, client, mdi->name, value); 345 } 346 347 void _broadcast_md_channel(ModDataInfo *mdi, Channel *channel, ModData *md) 348 { 349 const char *value = md ? mdi->serialize(md) : NULL; 350 351 broadcast_md_channel_cmd(NULL, &me, channel, mdi->name, value); 352 } 353 354 void _broadcast_md_member(ModDataInfo *mdi, Channel *channel, Member *m, ModData *md) 355 { 356 const char *value = md ? mdi->serialize(md) : NULL; 357 358 broadcast_md_member_cmd(NULL, &me, channel, m->client, mdi->name, value); 359 } 360 361 void _broadcast_md_membership(ModDataInfo *mdi, Client *client, Membership *m, ModData *md) 362 { 363 const char *value = md ? mdi->serialize(md) : NULL; 364 365 broadcast_md_membership_cmd(NULL, &me, client, m->channel, mdi->name, value); 366 } 367 368 void _broadcast_md_globalvar(ModDataInfo *mdi, ModData *md) 369 { 370 const char *value = md ? mdi->serialize(md) : NULL; 371 372 broadcast_md_globalvar_cmd(NULL, &me, mdi->name, value); 373 } 374 375 /** Send all moddata attached to client 'client' to remote server 'srv' (if the module wants this), called by .. */ 376 void _send_moddata_client(Client *srv, Client *client) 377 { 378 ModDataInfo *mdi; 379 380 for (mdi = MDInfo; mdi; mdi = mdi->next) 381 { 382 if ((mdi->type == MODDATATYPE_CLIENT) && mdi->sync && mdi->serialize) 383 { 384 const char *value = mdi->serialize(&moddata_client(client, mdi)); 385 if (value) 386 sendto_one(srv, NULL, ":%s MD %s %s %s :%s", 387 me.id, "client", client->id, mdi->name, value); 388 } 389 } 390 } 391 392 /** Enhance the command with moddata message tags, so we can send 393 * traffic like @s2s-md/certfp=xxxxx UID .... 394 */ 395 void _moddata_add_s2s_mtags(Client *client, MessageTag **mtags_list) 396 { 397 ModDataInfo *mdi; 398 char name[128]; 399 400 for (mdi = MDInfo; mdi; mdi = mdi->next) 401 { 402 if ((mdi->type == MODDATATYPE_CLIENT) && (mdi->sync == MODDATA_SYNC_EARLY) && mdi->serialize) 403 { 404 MessageTag *m; 405 const char *value = mdi->serialize(&moddata_client(client, mdi)); 406 if (!value) 407 continue; 408 snprintf(name, sizeof(name), "s2s-md/%s", mdi->name); 409 410 m = safe_alloc(sizeof(MessageTag)); 411 safe_strdup(m->name, name); 412 safe_strdup(m->value, value); 413 AddListItem(m, *mtags_list); 414 } 415 } 416 } 417 418 /** Extract the s2s-md/<moddataname> tags again from an incoming command, 419 * eg @s2s-md/certfp=xxxxx UID .... 420 */ 421 void _moddata_extract_s2s_mtags(Client *client, MessageTag *mtags) 422 { 423 MessageTag *m; 424 ModDataInfo *md; 425 426 for (m = mtags; m; m = m->next) 427 { 428 if (!strncmp(m->name, "s2s-md/", 7)) 429 { 430 char *varname = m->name + 7; 431 char *value = m->value; 432 433 if (!value) 434 continue; 435 436 md = findmoddata_byname(varname, MODDATATYPE_CLIENT); 437 if (!md || !md->unserialize) 438 continue; 439 440 if (!md_access_check(client, md, client)) 441 return; 442 443 md->unserialize(value, &moddata_client(client, md)); 444 } 445 } 446 } 447 448 /** Send all moddata attached to channel 'channel' to remote server 'srv' (if the module wants this), called by SJOIN */ 449 void _send_moddata_channel(Client *srv, Channel *channel) 450 { 451 ModDataInfo *mdi; 452 453 for (mdi = MDInfo; mdi; mdi = mdi->next) 454 { 455 if ((mdi->type == MODDATATYPE_CHANNEL) && mdi->sync && mdi->serialize) 456 { 457 const char *value = mdi->serialize(&moddata_channel(channel, mdi)); 458 if (value) 459 sendto_one(srv, NULL, ":%s MD %s %s %s :%s", 460 me.id, "channel", channel->name, mdi->name, value); 461 } 462 } 463 } 464 465 /** Send all moddata attached to member & memberships for 'channel' to remote server 'srv' (if the module wants this), called by SJOIN */ 466 void _send_moddata_members(Client *srv) 467 { 468 ModDataInfo *mdi; 469 Channel *channel; 470 Client *client; 471 472 for (channel = channels; channel; channel = channel->nextch) 473 { 474 Member *m; 475 for (m = channel->members; m; m = m->next) 476 { 477 client = m->client; 478 if (client->direction == srv) 479 continue; /* from srv's direction */ 480 for (mdi = MDInfo; mdi; mdi = mdi->next) 481 { 482 if ((mdi->type == MODDATATYPE_MEMBER) && mdi->sync && mdi->serialize) 483 { 484 const char *value = mdi->serialize(&moddata_member(m, mdi)); 485 if (value) 486 sendto_one(srv, NULL, ":%s MD %s %s:%s %s :%s", 487 me.id, "member", channel->name, client->id, mdi->name, value); 488 } 489 } 490 } 491 } 492 493 list_for_each_entry(client, &client_list, client_node) 494 { 495 Membership *m; 496 if (!IsUser(client) || !client->user) 497 continue; 498 499 if (client->direction == srv) 500 continue; /* from srv's direction */ 501 502 for (m = client->user->channel; m; m = m->next) 503 { 504 for (mdi = MDInfo; mdi; mdi = mdi->next) 505 { 506 if ((mdi->type == MODDATATYPE_MEMBERSHIP) && mdi->sync && mdi->serialize) 507 { 508 const char *value = mdi->serialize(&moddata_membership(m, mdi)); 509 if (value) 510 sendto_one(srv, NULL, ":%s MD %s %s:%s %s :%s", 511 me.id, "membership", client->id, m->channel->name, mdi->name, value); 512 } 513 } 514 } 515 } 516 } 517 518 /** Broadcast moddata attached to client 'client' to all servers. */ 519 void _broadcast_moddata_client(Client *client) 520 { 521 Client *acptr; 522 523 list_for_each_entry(acptr, &server_list, special_node) 524 { 525 send_moddata_client(acptr, client); 526 } 527 }