unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
api-usermode.c (9943B)
1 /************************************************************************ 2 * IRC - Internet Relay Chat, src/api-usermode.c 3 * (C) 1999-2000 Carsten Munk (Techie/Stskeeps) <stskeeps@tspre.org> 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 char umodestring[UMODETABLESZ+1]; 26 27 /** User modes and their handlers */ 28 Umode *usermodes = NULL; 29 30 long UMODE_INVISIBLE = 0L; /* makes user invisible */ 31 long UMODE_OPER = 0L; /* Operator */ 32 long UMODE_REGNICK = 0L; /* Nick set by services as registered */ 33 long UMODE_SERVNOTICE = 0L; /* server notices such as kill */ 34 long UMODE_HIDE = 0L; /* Hide from Nukes */ 35 long UMODE_SECURE = 0L; /* User is a secure connect */ 36 long UMODE_DEAF = 0L; /* Deaf */ 37 long UMODE_HIDEOPER = 0L; /* Hide oper mode */ 38 long UMODE_SETHOST = 0L; /* Used sethost */ 39 long UMODE_HIDLE = 0L; /* Hides the idle time of opers */ 40 41 long SNO_KILLS = 0L; 42 long SNO_CLIENT = 0L; 43 long SNO_FLOOD = 0L; 44 long SNO_FCLIENT = 0L; 45 long SNO_JUNK = 0L; 46 long SNO_VHOST = 0L; 47 long SNO_EYES = 0L; 48 long SNO_TKL = 0L; 49 long SNO_NICKCHANGE = 0L; 50 long SNO_FNICKCHANGE = 0L; 51 long SNO_QLINE = 0L; 52 long SNO_SPAMF = 0L; 53 long SNO_SNOTICE = 0L; 54 long SNO_OPER = 0L; 55 56 long AllUmodes; /* All umodes */ 57 long SendUmodes; /* All umodes which are sent to other servers (global umodes) */ 58 59 /* Forward declarations */ 60 int umode_hidle_allow(Client *client, int what); 61 static void unload_usermode_commit(Umode *m); 62 63 void umode_init(void) 64 { 65 /* Some built-in modes */ 66 UmodeAdd(NULL, 'i', UMODE_GLOBAL, 0, umode_allow_all, &UMODE_INVISIBLE); 67 UmodeAdd(NULL, 'o', UMODE_GLOBAL, 1, umode_allow_opers, &UMODE_OPER); 68 UmodeAdd(NULL, 'r', UMODE_GLOBAL, 0, umode_allow_none, &UMODE_REGNICK); 69 UmodeAdd(NULL, 's', UMODE_LOCAL, 0, umode_allow_all, &UMODE_SERVNOTICE); 70 UmodeAdd(NULL, 'x', UMODE_GLOBAL, 0, umode_allow_all, &UMODE_HIDE); 71 UmodeAdd(NULL, 'z', UMODE_GLOBAL, 0, umode_allow_none, &UMODE_SECURE); 72 UmodeAdd(NULL, 'd', UMODE_GLOBAL, 0, umode_allow_all, &UMODE_DEAF); 73 UmodeAdd(NULL, 'H', UMODE_GLOBAL, 1, umode_allow_opers, &UMODE_HIDEOPER); 74 UmodeAdd(NULL, 't', UMODE_GLOBAL, 0, umode_allow_unset, &UMODE_SETHOST); 75 UmodeAdd(NULL, 'I', UMODE_GLOBAL, 0, umode_hidle_allow, &UMODE_HIDLE); 76 } 77 78 void make_umodestr(void) 79 { 80 Umode *um; 81 char *p = umodestring; 82 83 for (um=usermodes; um; um = um->next) 84 if (um->letter) 85 *p++ = um->letter; 86 *p = '\0'; 87 } 88 89 static char previous_umodestring[256]; 90 91 void umodes_check_for_changes(void) 92 { 93 make_umodestr(); 94 safe_strdup(me.server->features.usermodes, umodestring); 95 96 if (!*previous_umodestring) 97 { 98 strlcpy(previous_umodestring, umodestring, sizeof(previous_umodestring)); 99 return; /* not booted yet. then we are done here. */ 100 } 101 102 if (*previous_umodestring && strcmp(umodestring, previous_umodestring)) 103 { 104 unreal_log(ULOG_INFO, "mode", "USER_MODES_CHANGED", NULL, 105 "User modes changed at runtime: $old_user_modes -> $new_user_modes", 106 log_data_string("old_user_modes", previous_umodestring), 107 log_data_string("new_user_modes", umodestring)); 108 /* Broadcast change to all (locally connected) servers */ 109 sendto_server(NULL, 0, 0, NULL, "PROTOCTL USERMODES=%s", umodestring); 110 } 111 112 strlcpy(previous_umodestring, umodestring, sizeof(previous_umodestring)); 113 } 114 115 void usermode_add_sorted(Umode *n) 116 { 117 Umode *m; 118 119 if (usermodes == NULL) 120 { 121 usermodes = n; 122 return; 123 } 124 125 for (m = usermodes; m; m = m->next) 126 { 127 if (m->letter == '\0') 128 abort(); 129 if (sort_character_lowercase_before_uppercase(n->letter, m->letter)) 130 { 131 /* Insert us before */ 132 if (m->prev) 133 m->prev->next = n; 134 else 135 usermodes = n; /* new head */ 136 n->prev = m->prev; 137 138 n->next = m; 139 m->prev = n; 140 return; 141 } 142 if (!m->next) 143 { 144 /* Append us at end */ 145 m->next = n; 146 n->prev = m; 147 return; 148 } 149 } 150 } 151 152 153 /* UmodeAdd: 154 * Add a usermode with character 'ch', if global is set to 1 the usermode is global 155 * (sent to other servers) otherwise it's a local usermode 156 */ 157 Umode *UmodeAdd(Module *module, char ch, int global, int unset_on_deoper, int (*allowed)(Client *client, int what), long *mode) 158 { 159 Umode *um; 160 int existing = 0; 161 162 for (um=usermodes; um; um = um->next) 163 { 164 if (um->letter == ch) 165 { 166 if (um->unloaded) 167 { 168 um->unloaded = 0; 169 existing = 1; 170 break; 171 } else { 172 if (module) 173 module->errorcode = MODERR_EXISTS; 174 return NULL; 175 } 176 } 177 } 178 179 if (!um) 180 { 181 /* Not found, create */ 182 long l, found = 0; 183 for (l = 1; l < LONG_MAX/2; l *= 2) 184 { 185 found = 0; 186 for (um=usermodes; um; um = um->next) 187 { 188 if (um->mode == l) 189 { 190 found = 1; 191 break; 192 } 193 } 194 if (!found) 195 break; 196 } 197 /* If 'found' is still true, then we are out of space */ 198 if (found) 199 { 200 unreal_log(ULOG_ERROR, "module", "USER_MODE_OUT_OF_SPACE", NULL, 201 "UmodeAdd: out of space!!!"); 202 if (module) 203 module->errorcode = MODERR_NOSPACE; 204 return NULL; 205 } 206 um = safe_alloc(sizeof(Umode)); 207 um->letter = ch; 208 um->mode = l; 209 usermode_add_sorted(um); 210 } 211 212 um->letter = ch; 213 um->allowed = allowed; 214 um->unset_on_deoper = unset_on_deoper; 215 make_umodestr(); 216 AllUmodes |= um->mode; 217 if (global) 218 SendUmodes |= um->mode; 219 *mode = um->mode; 220 um->owner = module; 221 if (module) 222 { 223 ModuleObject *umodeobj = safe_alloc(sizeof(ModuleObject)); 224 umodeobj->object.umode = um; 225 umodeobj->type = MOBJ_UMODE; 226 AddListItem(umodeobj, module->objects); 227 module->errorcode = MODERR_NOERROR; 228 } 229 return um; 230 } 231 232 233 void UmodeDel(Umode *umode) 234 { 235 /* Always free the module object */ 236 if (umode->owner) 237 { 238 ModuleObject *umodeobj; 239 for (umodeobj = umode->owner->objects; umodeobj; umodeobj = umodeobj->next) 240 { 241 if (umodeobj->type == MOBJ_UMODE && umodeobj->object.umode == umode) 242 { 243 DelListItem(umodeobj, umode->owner->objects); 244 safe_free(umodeobj); 245 break; 246 } 247 } 248 umode->owner = NULL; 249 } 250 251 /* Whether we can actually (already) free the Umode depends... */ 252 253 if (loop.rehashing) 254 umode->unloaded = 1; 255 else 256 unload_usermode_commit(umode); 257 } 258 259 int umode_allow_all(Client *client, int what) 260 { 261 return 1; 262 } 263 264 int umode_allow_unset(Client *client, int what) 265 { 266 if (!MyUser(client)) 267 return 1; 268 if (what == MODE_DEL) 269 return 1; 270 return 0; 271 } 272 273 int umode_allow_none(Client *client, int what) 274 { 275 if (MyUser(client)) 276 return 0; 277 return 1; 278 } 279 280 int umode_allow_opers(Client *client, int what) 281 { 282 if (MyUser(client)) 283 return IsOper(client) ? 1 : 0; 284 else 285 return 1; 286 } 287 288 int umode_hidle_allow(Client *client, int what) 289 { 290 if (!MyUser(client)) 291 return 1; 292 if (iConf.hide_idle_time == HIDE_IDLE_TIME_OPER_USERMODE) 293 return IsOper(client) ? 1 : 0; 294 if (iConf.hide_idle_time == HIDE_IDLE_TIME_USERMODE) 295 return 1; 296 return 0; /* if set::hide-idle-time is 'never' or 'always' then +I makes no sense */ 297 } 298 299 static void unload_usermode_commit(Umode *um) 300 { 301 Client *client; 302 long removed_umode; 303 304 if (!um) 305 return; 306 307 removed_umode = um->mode; 308 309 /* First send the -mode regarding all users */ 310 list_for_each_entry(client, &lclient_list, lclient_node) 311 { 312 if (MyUser(client) && (client->umodes & removed_umode)) 313 { 314 long oldumode = client->umodes; 315 client->umodes &= ~(removed_umode); 316 send_umode_out(client, 1, oldumode); 317 } 318 } 319 320 /* Then unload the mode */ 321 DelListItem(um, usermodes); 322 safe_free(um); 323 make_umodestr(); 324 } 325 326 void unload_all_unused_umodes(void) 327 { 328 Umode *um, *um_next; 329 330 for (um=usermodes; um; um = um_next) 331 { 332 um_next = um->next; 333 if (um->letter && um->unloaded) 334 unload_usermode_commit(um); 335 } 336 } 337 338 /** 339 * This function removes any oper-only snomasks when the user is no 340 * longer an IRC Operator. 341 * This used to be a bit more complex but nowadays we just erase all 342 * snomasks since all of them are IRCOp-only. Easy. 343 */ 344 void remove_all_snomasks(Client *client) 345 { 346 safe_free(client->user->snomask); 347 client->umodes &= ~UMODE_SERVNOTICE; 348 } 349 350 /* 351 * This function removes any oper-only user modes from the user. 352 * You may also want to call remove_all_snomasks(), see above. 353 */ 354 void remove_oper_modes(Client *client) 355 { 356 Umode *um; 357 358 for (um = usermodes; um; um = um->next) 359 { 360 if (um->unset_on_deoper) 361 client->umodes &= ~um->mode; 362 } 363 364 /* Bit of a hack, since this is a dynamic permission umode */ 365 if (iConf.hide_idle_time == HIDE_IDLE_TIME_OPER_USERMODE) 366 client->umodes &= ~UMODE_HIDLE; 367 } 368 369 void remove_oper_privileges(Client *client, int broadcast_mode_change) 370 { 371 long oldumodes = client->umodes; 372 remove_oper_modes(client); 373 remove_all_snomasks(client); 374 if (broadcast_mode_change && (client->umodes != oldumodes)) 375 send_umode_out(client, 1, oldumodes); 376 if (MyUser(client)) /* only do if it's our client, remote servers will send a SWHOIS cmd */ 377 swhois_delete(client, "oper", "*", &me, NULL); 378 } 379 380 /** Return long integer mode for a user mode character (eg: 'x' -> 0x10) */ 381 long find_user_mode(char letter) 382 { 383 Umode *um; 384 385 for (um = usermodes; um; um = um->next) 386 if ((um->letter == letter) && !um->unloaded) 387 return um->mode; 388 389 return 0; 390 } 391 392 /** Returns 1 if user has this user mode set and 0 if not */ 393 int has_user_mode(Client *client, char mode) 394 { 395 long m = find_user_mode(mode); 396 397 if (client->umodes & m) 398 return 1; /* Yes, user has this mode */ 399 400 return 0; /* Mode does not exist or not set */ 401 }