unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
whois.c (21206B)
1 /* 2 * Unreal Internet Relay Chat Daemon, src/modules/whois.c 3 * (C) 2000-2001 Carsten V. Munk and the UnrealIRCd Team 4 * (C) 2003-2021 Bram Matthys and the UnrealIRCd team 5 * Moved to modules by Fish (Justin Hammond) in 2001 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 1, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 */ 21 22 #include "unrealircd.h" 23 24 /* Structs */ 25 ModuleHeader MOD_HEADER 26 = { 27 "whois", /* Name of module */ 28 "5.0", /* Version */ 29 "command /whois", /* Short description of module */ 30 "UnrealIRCd Team", 31 "unrealircd-6", 32 }; 33 34 typedef enum WhoisConfigUser { 35 WHOIS_CONFIG_USER_EVERYONE = 1, 36 WHOIS_CONFIG_USER_SELF = 2, 37 WHOIS_CONFIG_USER_OPER = 3, 38 } WhoisConfigUser; 39 #define HIGHEST_WHOIS_CONFIG_USER_VALUE 3 /* adjust this if you edit the enum above !! */ 40 41 //this one is in include/struct.h because it needs full API exposure: 42 //typedef enum WhoisConfigDetails { 43 // ... 44 //} WhoisConfigDetails; 45 // 46 47 typedef struct WhoisConfig WhoisConfig; 48 struct WhoisConfig { 49 WhoisConfig *prev, *next; 50 char *name; 51 WhoisConfigDetails permissions[HIGHEST_WHOIS_CONFIG_USER_VALUE+1]; 52 }; 53 54 /* Global variables */ 55 WhoisConfig *whoisconfig = NULL; 56 57 /* Forward declarations */ 58 WhoisConfigDetails _whois_get_policy(Client *client, Client *target, const char *name); 59 CMD_FUNC(cmd_whois); 60 static int whois_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs); 61 static int whois_config_run(ConfigFile *cf, ConfigEntry *ce, int type); 62 static void whois_config_setdefaults(void); 63 64 MOD_TEST() 65 { 66 MARK_AS_OFFICIAL_MODULE(modinfo); 67 EfunctionAdd(modinfo->handle, EFUNC_WHOIS_GET_POLICY, TO_INTFUNC(_whois_get_policy)); 68 HookAdd(modinfo->handle, HOOKTYPE_CONFIGTEST, 0, whois_config_test); 69 return MOD_SUCCESS; 70 } 71 72 MOD_INIT() 73 { 74 MARK_AS_OFFICIAL_MODULE(modinfo); 75 CommandAdd(modinfo->handle, "WHOIS", cmd_whois, MAXPARA, CMD_USER); 76 HookAdd(modinfo->handle, HOOKTYPE_CONFIGRUN, 0, whois_config_run); 77 whois_config_setdefaults(); 78 return MOD_SUCCESS; 79 } 80 81 MOD_LOAD() 82 { 83 return MOD_SUCCESS; 84 } 85 86 MOD_UNLOAD() 87 { 88 return MOD_SUCCESS; 89 } 90 91 static WhoisConfig *find_whois_config(const char *name) 92 { 93 WhoisConfig *w; 94 for (w = whoisconfig; w; w = w->next) 95 if (!strcmp(w->name, name)) 96 return w; 97 return NULL; 98 } 99 100 /* Lazy helper for whois_config_setdefaults */ 101 static void whois_config_add(const char *name, WhoisConfigUser user, WhoisConfigDetails details) 102 { 103 WhoisConfig *w = find_whois_config(name); 104 105 if (!w) 106 { 107 /* New one */ 108 w = safe_alloc(sizeof(WhoisConfig)); 109 safe_strdup(w->name, name); 110 AddListItem(w, whoisconfig); 111 } 112 w->permissions[user] = details; 113 } 114 115 static void whois_config_setdefaults(void) 116 { 117 whois_config_add("basic", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 118 119 whois_config_add("modes", WHOIS_CONFIG_USER_SELF, WHOIS_CONFIG_DETAILS_FULL); 120 whois_config_add("modes", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 121 122 whois_config_add("realhost", WHOIS_CONFIG_USER_SELF, WHOIS_CONFIG_DETAILS_FULL); 123 whois_config_add("realhost", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 124 125 whois_config_add("registered-nick", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 126 127 whois_config_add("channels", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_LIMITED); 128 whois_config_add("channels", WHOIS_CONFIG_USER_SELF, WHOIS_CONFIG_DETAILS_FULL); 129 whois_config_add("channels", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 130 131 whois_config_add("server", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 132 133 whois_config_add("away", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 134 135 whois_config_add("oper", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_LIMITED); 136 whois_config_add("oper", WHOIS_CONFIG_USER_SELF, WHOIS_CONFIG_DETAILS_FULL); 137 whois_config_add("oper", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 138 139 whois_config_add("secure", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_LIMITED); 140 whois_config_add("secure", WHOIS_CONFIG_USER_SELF, WHOIS_CONFIG_DETAILS_FULL); 141 whois_config_add("secure", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 142 143 whois_config_add("bot", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 144 145 whois_config_add("services", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 146 147 whois_config_add("reputation", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 148 149 whois_config_add("security-groups", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 150 151 whois_config_add("geo", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 152 153 whois_config_add("certfp", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 154 155 whois_config_add("shunned", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 156 157 whois_config_add("account", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 158 159 whois_config_add("swhois", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_FULL); 160 161 whois_config_add("idle", WHOIS_CONFIG_USER_EVERYONE, WHOIS_CONFIG_DETAILS_LIMITED); 162 whois_config_add("idle", WHOIS_CONFIG_USER_SELF, WHOIS_CONFIG_DETAILS_FULL); 163 whois_config_add("idle", WHOIS_CONFIG_USER_OPER, WHOIS_CONFIG_DETAILS_FULL); 164 } 165 166 static void whois_free_config(void) 167 { 168 } 169 170 static WhoisConfigUser whois_config_user_strtovalue(const char *str) 171 { 172 if (!strcmp(str, "everyone")) 173 return WHOIS_CONFIG_USER_EVERYONE; 174 if (!strcmp(str, "self")) 175 return WHOIS_CONFIG_USER_SELF; 176 if (!strcmp(str, "oper")) 177 return WHOIS_CONFIG_USER_OPER; 178 return 0; 179 } 180 181 static WhoisConfigDetails whois_config_details_strtovalue(const char *str) 182 { 183 if (!strcmp(str, "full")) 184 return WHOIS_CONFIG_DETAILS_FULL; 185 if (!strcmp(str, "limited")) 186 return WHOIS_CONFIG_DETAILS_LIMITED; 187 if (!strcmp(str, "none")) 188 return WHOIS_CONFIG_DETAILS_NONE; 189 return 0; 190 } 191 192 static int whois_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) 193 { 194 int errors = 0; 195 ConfigEntry *cep, *cepp; 196 197 if (type != CONFIG_SET) 198 return 0; 199 200 /* We are only interrested in set::whois-details.. */ 201 if (!ce || strcmp(ce->name, "whois-details")) 202 return 0; 203 204 for (cep = ce->items; cep; cep = cep->next) 205 { 206 if (cep->value) 207 { 208 config_error("%s:%i: set::whois-details::%s item has a value, which is unexpected. Check your syntax!", 209 cep->file->filename, cep->line_number, cep->name); 210 errors++; 211 continue; 212 } 213 for (cepp = cep->items; cepp; cepp = cepp->next) 214 { 215 if (!whois_config_user_strtovalue(cepp->name)) 216 { 217 config_error("%s:%i: set::whois-details::%s contains unknown user category called '%s', must be one of: everyone, self, ircop", 218 cepp->file->filename, cepp->line_number, cep->name, cepp->name); 219 errors++; 220 continue; 221 } else 222 if (!cepp->value || !whois_config_details_strtovalue(cepp->value)) 223 { 224 config_error("%s:%i: set::whois-details::%s contains unknown details type '%s', must be one of: full, limited, none", 225 cepp->file->filename, cepp->line_number, cep->name, cepp->name); 226 errors++; 227 continue; 228 } /* else it is good */ 229 } 230 } 231 232 *errs = errors; 233 return errors ? -1 : 1; 234 } 235 236 static int whois_config_run(ConfigFile *cf, ConfigEntry *ce, int type) 237 { 238 ConfigEntry *cep, *cepp; 239 240 if (type != CONFIG_SET) 241 return 0; 242 243 /* We are only interrested in set::whois-details.. */ 244 if (!ce || strcmp(ce->name, "whois-details")) 245 return 0; 246 247 for (cep = ce->items; cep; cep = cep->next) 248 { 249 WhoisConfig *w = find_whois_config(cep->name); 250 if (!w) 251 { 252 /* New one */ 253 w = safe_alloc(sizeof(WhoisConfig)); 254 safe_strdup(w->name, cep->name); 255 AddListItem(w, whoisconfig); 256 } 257 for (cepp = cep->items; cepp; cepp = cepp->next) 258 { 259 WhoisConfigUser user = whois_config_user_strtovalue(cepp->name); 260 WhoisConfigDetails details = whois_config_details_strtovalue(cepp->value); 261 w->permissions[user] = details; 262 } 263 } 264 return 1; 265 } 266 267 /** Get set::whois-details policy for an item. 268 * @param client The client doing the /WHOIS 269 * @param target The client being whoised, so the one to show all details for 270 * @param name The name of the whois item (eg "modes") 271 */ 272 WhoisConfigDetails _whois_get_policy(Client *client, Client *target, const char *name) 273 { 274 WhoisConfig *w = find_whois_config(name); 275 if (!w) 276 return WHOIS_CONFIG_DETAILS_DEFAULT; 277 if ((client == target) && (w->permissions[WHOIS_CONFIG_USER_SELF] > 0)) 278 return w->permissions[WHOIS_CONFIG_USER_SELF]; 279 if (IsOper(client) && (w->permissions[WHOIS_CONFIG_USER_OPER] > 0)) 280 return w->permissions[WHOIS_CONFIG_USER_OPER]; 281 if (w->permissions[WHOIS_CONFIG_USER_EVERYONE] > 0) 282 return w->permissions[WHOIS_CONFIG_USER_EVERYONE]; 283 return WHOIS_CONFIG_DETAILS_NONE; 284 } 285 286 /* WHOIS command. 287 * parv[1] = list of nicks (comma separated) 288 */ 289 CMD_FUNC(cmd_whois) 290 { 291 Membership *lp; 292 Client *target; 293 Channel *channel; 294 char *nick, *tmp; 295 char *p = NULL; 296 int len, mlen; 297 char querybuf[BUFSIZE]; 298 char buf[BUFSIZE]; 299 int ntargets = 0; 300 int maxtargets = max_targets_for_command("WHOIS"); 301 302 if (parc < 2) 303 { 304 sendnumeric(client, ERR_NONICKNAMEGIVEN); 305 return; 306 } 307 308 if (parc > 2) 309 { 310 if (hunt_server(client, recv_mtags, "WHOIS", 1, parc, parv) != HUNTED_ISME) 311 return; 312 parv[1] = parv[2]; 313 } 314 315 strlcpy(querybuf, parv[1], sizeof(querybuf)); 316 317 for (tmp = canonize(parv[1]); (nick = strtoken(&p, tmp, ",")); tmp = NULL) 318 { 319 unsigned char showchannel, wilds, hideoper; /* <- these are all boolean-alike */ 320 NameValuePrioList *list = NULL, *e; 321 int policy; /* for temporary stuff */ 322 323 if (MyUser(client) && (++ntargets > maxtargets)) 324 { 325 sendnumeric(client, ERR_TOOMANYTARGETS, nick, maxtargets, "WHOIS"); 326 break; 327 } 328 329 /* We do not support "WHOIS *" */ 330 wilds = (strchr(nick, '?') || strchr(nick, '*')); 331 if (wilds) 332 continue; 333 334 target = find_user(nick, NULL); 335 if (!target) 336 { 337 sendnumeric(client, ERR_NOSUCHNICK, nick); 338 continue; 339 } 340 341 /* Ok, from this point we are going to proceed with the WHOIS. 342 * The idea here is NOT to send any lines, so don't call sendto functions. 343 * Instead, use add_nvplist_numeric() and add_nvplist_numeric_fmt() 344 * to add items to the whois list. 345 * Then at the end of this loop we call modules who can also add/remove 346 * whois lines, and only after that we FINALLY send all the whois lines 347 * in one go. 348 */ 349 350 hideoper = 0; 351 if (IsHideOper(target) && (target != client) && !IsOper(client)) 352 hideoper = 1; 353 354 if (whois_get_policy(client, target, "basic") > WHOIS_CONFIG_DETAILS_NONE) 355 { 356 add_nvplist_numeric(&list, -1000000, "basic", client, RPL_WHOISUSER, target->name, 357 target->user->username, 358 IsHidden(target) ? target->user->virthost : target->user->realhost, 359 target->info); 360 } 361 362 if (whois_get_policy(client, target, "modes") > WHOIS_CONFIG_DETAILS_NONE) 363 { 364 add_nvplist_numeric(&list, -100000, "modes", client, RPL_WHOISMODES, target->name, 365 get_usermode_string(target), target->user->snomask ? target->user->snomask : ""); 366 } 367 if (whois_get_policy(client, target, "realhost") > WHOIS_CONFIG_DETAILS_NONE) 368 { 369 add_nvplist_numeric(&list, -90000, "realhost", client, RPL_WHOISHOST, target->name, 370 (MyConnect(target) && strcmp(target->ident, "unknown")) ? target->ident : "*", 371 target->user->realhost, target->ip ? target->ip : ""); 372 } 373 374 if (IsRegNick(target) && (whois_get_policy(client, target, "registered-nick") > WHOIS_CONFIG_DETAILS_NONE)) 375 { 376 add_nvplist_numeric(&list, -80000, "registered-nick", client, RPL_WHOISREGNICK, target->name); 377 } 378 379 /* The following code deals with channels */ 380 policy = whois_get_policy(client, target, "channels"); 381 if (policy > WHOIS_CONFIG_DETAILS_NONE) 382 { 383 int channel_whois_lines = 0; 384 mlen = strlen(me.name) + strlen(client->name) + 10 + strlen(target->name); 385 for (len = 0, *buf = '\0', lp = target->user->channel; lp; lp = lp->next) 386 { 387 Hook *h; 388 int ret = EX_ALLOW; 389 int operoverride = 0; 390 391 channel = lp->channel; 392 showchannel = 0; 393 394 if (ShowChannel(client, channel)) 395 showchannel = 1; 396 397 for (h = Hooks[HOOKTYPE_SEE_CHANNEL_IN_WHOIS]; h; h = h->next) 398 { 399 int n = (*(h->func.intfunc))(client, target, channel); 400 /* Hook return values: 401 * EX_ALLOW means 'yes is ok, as far as modules are concerned' 402 * EX_DENY means 'hide this channel, unless oper overriding' 403 * EX_ALWAYS_DENY means 'hide this channel, always' 404 * ... with the exception that we always show the channel if you /WHOIS yourself 405 */ 406 if (n == EX_DENY) 407 { 408 ret = EX_DENY; 409 } 410 else if (n == EX_ALWAYS_DENY) 411 { 412 ret = EX_ALWAYS_DENY; 413 break; 414 } 415 } 416 417 if (ret == EX_DENY) 418 showchannel = 0; 419 420 /* If the channel is normally hidden, but the user is an IRCOp, 421 * and has the channel:see:whois privilege, 422 * and set::whois-details for 'channels' has 'oper full', 423 * then show it: 424 */ 425 if (!showchannel && (ValidatePermissionsForPath("channel:see:whois",client,NULL,channel,NULL)) && (policy == WHOIS_CONFIG_DETAILS_FULL)) 426 { 427 showchannel = 1; /* OperOverride */ 428 operoverride = 1; 429 } 430 431 if ((ret == EX_ALWAYS_DENY) && (target != client)) 432 continue; /* a module asked us to really not expose this channel, so we don't (except target==ourselves). */ 433 434 /* This deals with target==client but also for unusual set::whois-details overrides 435 * such as 'everyone full' 436 */ 437 if (policy == WHOIS_CONFIG_DETAILS_FULL) 438 showchannel = 1; 439 440 if (showchannel) 441 { 442 if (len + strlen(channel->name) > (size_t)BUFSIZE - 4 - mlen) 443 { 444 add_nvplist_numeric_fmt(&list, -70500-channel_whois_lines, "channels", client, RPL_WHOISCHANNELS, 445 "%s :%s", target->name, buf); 446 channel_whois_lines++; 447 *buf = '\0'; 448 len = 0; 449 } 450 451 if (operoverride) 452 { 453 /* '?' and '!' both mean we can see the channel in /WHOIS and normally wouldn't, 454 * but there's still a slight difference between the two... 455 */ 456 if (!PubChannel(channel)) 457 { 458 /* '?' means it's a secret/private channel (too) */ 459 *(buf + len++) = '?'; 460 } 461 else 462 { 463 /* public channel but hidden in WHOIS (umode +p, service bot, etc) */ 464 *(buf + len++) = '!'; 465 } 466 } 467 468 if (!MyUser(client) || !HasCapability(client, "multi-prefix")) 469 { 470 /* Standard NAMES reply (single character) */ 471 char c = mode_to_prefix(*lp->member_modes); 472 if (c) 473 *(buf + len++) = c; 474 } 475 else 476 { 477 /* NAMES reply with all rights included (multi-prefix / NAMESX) */ 478 strcpy(buf + len, modes_to_prefix(lp->member_modes)); 479 len += strlen(buf + len); 480 } 481 if (len) 482 *(buf + len) = '\0'; 483 strcpy(buf + len, channel->name); 484 len += strlen(channel->name); 485 strcat(buf + len, " "); 486 len++; 487 } 488 } 489 490 if (buf[0] != '\0') 491 { 492 add_nvplist_numeric_fmt(&list, -70500-channel_whois_lines, "channels", client, RPL_WHOISCHANNELS, 493 "%s :%s", target->name, buf); 494 channel_whois_lines++; 495 } 496 } 497 498 if (!(IsULine(target) && !IsOper(client) && HIDE_ULINES) && 499 whois_get_policy(client, target, "server") > WHOIS_CONFIG_DETAILS_NONE) 500 { 501 add_nvplist_numeric(&list, -60000, "server", client, RPL_WHOISSERVER, 502 target->name, target->user->server, target->uplink->info); 503 } 504 505 if (target->user->away && (whois_get_policy(client, target, "away") > WHOIS_CONFIG_DETAILS_NONE)) 506 { 507 add_nvplist_numeric(&list, -50000, "away", client, RPL_AWAY, 508 target->name, target->user->away); 509 } 510 511 if (IsOper(target) && !hideoper) 512 { 513 policy = whois_get_policy(client, target, "oper"); 514 if (policy == WHOIS_CONFIG_DETAILS_FULL) 515 { 516 const char *operlogin = get_operlogin(target); 517 const char *operclass = get_operclass(target); 518 519 if (operlogin && operclass) 520 { 521 add_nvplist_numeric_fmt(&list, -40000, "oper", client, RPL_WHOISOPERATOR, 522 "%s :is %s (%s) [%s]", 523 target->name, "an IRC Operator", operlogin, operclass); 524 } else 525 if (operlogin) 526 { 527 add_nvplist_numeric_fmt(&list, -40000, "oper", client, RPL_WHOISOPERATOR, 528 "%s :is %s (%s)", 529 target->name, "an IRC Operator", operlogin); 530 } else 531 { 532 add_nvplist_numeric(&list, -40000, "oper", client, RPL_WHOISOPERATOR, 533 target->name, "an IRC Operator"); 534 } 535 } else 536 if (policy == WHOIS_CONFIG_DETAILS_LIMITED) 537 { 538 add_nvplist_numeric(&list, -40000, "oper", client, RPL_WHOISOPERATOR, 539 target->name, "an IRC Operator"); 540 } 541 } 542 543 if (target->umodes & UMODE_SECURE) 544 { 545 policy = whois_get_policy(client, target, "secure"); 546 if (policy == WHOIS_CONFIG_DETAILS_LIMITED) 547 { 548 add_nvplist_numeric(&list, -30000, "secure", client, RPL_WHOISSECURE, 549 target->name, "is using a Secure Connection"); 550 } else 551 if (policy == WHOIS_CONFIG_DETAILS_FULL) 552 { 553 const char *ciphers = tls_get_cipher(target); 554 if (ciphers) 555 { 556 add_nvplist_numeric_fmt(&list, -30000, "secure", client, RPL_WHOISSECURE, 557 "%s :is using a Secure Connection [%s]", 558 target->name, ciphers); 559 } else { 560 add_nvplist_numeric(&list, -30000, "secure", client, RPL_WHOISSECURE, 561 target->name, "is using a Secure Connection"); 562 } 563 } 564 } 565 566 /* The following code deals with security-groups */ 567 policy = whois_get_policy(client, target, "security-groups"); 568 if ((policy > WHOIS_CONFIG_DETAILS_NONE) && !IsULine(target)) 569 { 570 SecurityGroup *s; 571 int security_groups_whois_lines = 0; 572 573 mlen = strlen(me.name) + strlen(client->name) + 10 + strlen(target->name) + strlen("is in security-groups: "); 574 575 if (user_allowed_by_security_group_name(target, "known-users")) 576 strlcpy(buf, "known-users,", sizeof(buf)); 577 else 578 strlcpy(buf, "unknown-users,", sizeof(buf)); 579 len = strlen(buf); 580 581 for (s = securitygroups; s; s = s->next) 582 { 583 if (len + strlen(s->name) > (size_t)BUFSIZE - 4 - mlen) 584 { 585 buf[len-1] = '\0'; 586 add_nvplist_numeric_fmt(&list, -15000-security_groups_whois_lines, "security-groups", 587 target, RPL_WHOISSPECIAL, 588 "%s :is in security-groups: %s", target->name, buf); 589 security_groups_whois_lines++; 590 *buf = '\0'; 591 len = 0; 592 } 593 if (strcmp(s->name, "known-users") && user_allowed_by_security_group(target, s)) 594 { 595 strcpy(buf + len, s->name); 596 len += strlen(buf+len); 597 strcpy(buf + len, ","); 598 len++; 599 } 600 } 601 602 if (*buf) 603 { 604 buf[len-1] = '\0'; 605 add_nvplist_numeric_fmt(&list, -15000-security_groups_whois_lines, "security-groups", 606 client, RPL_WHOISSPECIAL, 607 "%s :is in security-groups: %s", target->name, buf); 608 security_groups_whois_lines++; 609 } 610 } 611 if (MyUser(target) && IsShunned(target) && (whois_get_policy(client, target, "shunned") > WHOIS_CONFIG_DETAILS_NONE)) 612 { 613 add_nvplist_numeric(&list, -20000, "shunned", client, RPL_WHOISSPECIAL, 614 target->name, "is shunned"); 615 } 616 617 if (target->user->swhois && (whois_get_policy(client, target, "swhois") > WHOIS_CONFIG_DETAILS_NONE)) 618 { 619 SWhois *s; 620 int swhois_lines = 0; 621 622 for (s = target->user->swhois; s; s = s->next) 623 { 624 if (hideoper && !IsOper(client) && s->setby && !strcmp(s->setby, "oper")) 625 continue; /* hide oper-based swhois entries */ 626 add_nvplist_numeric(&list, 100000+swhois_lines, "swhois", client, RPL_WHOISSPECIAL, 627 target->name, s->line); 628 swhois_lines++; 629 } 630 } 631 632 /* TODO: hmm.. this should be a bit more towards the beginning of the whois, no ? */ 633 if (IsLoggedIn(target) && (whois_get_policy(client, target, "account") > WHOIS_CONFIG_DETAILS_NONE)) 634 { 635 add_nvplist_numeric(&list, 200000, "account", client, RPL_WHOISLOGGEDIN, 636 target->name, target->user->account); 637 } 638 639 if (MyConnect(target)) 640 { 641 policy = whois_get_policy(client, target, "idle"); 642 /* If the policy is 'full' then show the idle time. 643 * If the policy is 'limited then show the idle time according to the +I rules 644 */ 645 if ((policy == WHOIS_CONFIG_DETAILS_FULL) || 646 ((policy == WHOIS_CONFIG_DETAILS_LIMITED) && !hide_idle_time(client, target))) 647 { 648 add_nvplist_numeric(&list, 500000, "idle", client, RPL_WHOISIDLE, 649 target->name, 650 (long long)(TStime() - target->local->idle_since), 651 (long long)target->local->creationtime); 652 } 653 } 654 655 RunHook(HOOKTYPE_WHOIS, client, target, &list); 656 657 for (e = list; e; e = e->next) 658 sendto_one(client, NULL, "%s", e->value); 659 660 free_nvplist(list); 661 } 662 sendnumeric(client, RPL_ENDOFWHOIS, querybuf); 663 }