1 /*
2 * Unreal Internet Relay Chat Daemon, src/s_extra.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 "struct.h"
24 #include "common.h"
25 #include "sys.h"
26 #include "numeric.h"
27 #include "msg.h"
28 #include "channel.h"
29 #include <time.h>
30 #include <sys/stat.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #ifdef _WIN32
36 #include <io.h>
37 #endif
38 #include <fcntl.h>
39 #include "h.h"
40 #include "proto.h"
41
42 ID_Copyright("(C) Carsten Munk 1999");
43
44 /* e->flag.type2:
45 * CONF_BAN_TYPE_AKILL banned by SVSFLINE ('global')
46 * CONF_BAN_TYPE_CONF banned by conf
47 * CONF_BAN_TYPE_TEMPORARY banned by /DCCDENY ('temporary')
48 * e->flag.type:
49 * DCCDENY_HARD Fully denied
50 * DCCDENY_SOFT Denied, but allowed to override via /DCCALLOW
51 */
52
53 /* checks if the dcc is blacklisted.
54 */
dcc_isforbidden(aClient * sptr,char * filename)55 ConfigItem_deny_dcc *dcc_isforbidden(aClient *sptr, char *filename)
56 {
57 ConfigItem_deny_dcc *d;
58 ConfigItem_allow_dcc *a;
59
60 if (!conf_deny_dcc || !filename)
61 return NULL;
62
63 for (d = conf_deny_dcc; d; d = (ConfigItem_deny_dcc *) d->next)
64 {
65 if ((d->flag.type == DCCDENY_HARD) && !match(d->filename, filename))
66 {
67 for (a = conf_allow_dcc; a; a = (ConfigItem_allow_dcc *) a->next)
68 {
69 if ((a->flag.type == DCCDENY_HARD) && !match(a->filename, filename))
70 return NULL;
71 }
72 return d;
73 }
74 }
75
76 return NULL;
77 }
78
79 /* checks if the dcc is discouraged ('soft bans').
80 */
dcc_isdiscouraged(aClient * sptr,char * filename)81 ConfigItem_deny_dcc *dcc_isdiscouraged(aClient *sptr, char *filename)
82 {
83 ConfigItem_deny_dcc *d;
84 ConfigItem_allow_dcc *a;
85
86 if (!conf_deny_dcc || !filename)
87 return NULL;
88
89 for (d = conf_deny_dcc; d; d = (ConfigItem_deny_dcc *) d->next)
90 {
91 if ((d->flag.type == DCCDENY_SOFT) && !match(d->filename, filename))
92 {
93 for (a = conf_allow_dcc; a; a = (ConfigItem_allow_dcc *) a->next)
94 {
95 if ((a->flag.type == DCCDENY_SOFT) && !match(a->filename, filename))
96 return NULL;
97 }
98 return d;
99 }
100 }
101
102 return NULL;
103 }
104
dcc_sync(aClient * sptr)105 void dcc_sync(aClient *sptr)
106 {
107 ConfigItem_deny_dcc *p;
108 for (p = conf_deny_dcc; p; p = (ConfigItem_deny_dcc *) p->next)
109 {
110 if (p->flag.type2 == CONF_BAN_TYPE_AKILL)
111 sendto_one(sptr, ":%s %s + %s :%s", me.name,
112 (IsToken(sptr) ? TOK_SVSFLINE : MSG_SVSFLINE),
113 p->filename, p->reason);
114 }
115 }
116
DCCdeny_add(char * filename,char * reason,int type,int type2)117 void DCCdeny_add(char *filename, char *reason, int type, int type2)
118 {
119 ConfigItem_deny_dcc *deny = NULL;
120
121 deny = (ConfigItem_deny_dcc *) MyMallocEx(sizeof(ConfigItem_deny_dcc));
122 deny->filename = strdup(filename);
123 deny->reason = strdup(reason);
124 deny->flag.type = type;
125 deny->flag.type2 = type2;
126 AddListItem(deny, conf_deny_dcc);
127 }
128
DCCdeny_del(ConfigItem_deny_dcc * deny)129 void DCCdeny_del(ConfigItem_deny_dcc *deny)
130 {
131 DelListItem(deny, conf_deny_dcc);
132 if (deny->filename)
133 MyFree(deny->filename);
134 if (deny->reason)
135 MyFree(deny->reason);
136 MyFree(deny);
137 }
138
dcc_wipe_services(void)139 void dcc_wipe_services(void)
140 {
141 ConfigItem_deny_dcc *dconf, *next;
142
143 for (dconf = conf_deny_dcc; dconf; dconf = (ConfigItem_deny_dcc *) next)
144 {
145 next = (ConfigItem_deny_dcc *)dconf->next;
146 if ((dconf->flag.type2 == CONF_BAN_TYPE_AKILL))
147 {
148 DelListItem(dconf, conf_deny_dcc);
149 if (dconf->filename)
150 MyFree(dconf->filename);
151 if (dconf->reason)
152 MyFree(dconf->reason);
153 MyFree(dconf);
154 }
155 }
156
157 }
158
159 /* The dccallow functions below are all taken from bahamut (1.8.1).
160 * Well, with some small modifications of course. -- Syzop
161 */
on_dccallow_list(aClient * to,aClient * from)162 int on_dccallow_list(aClient *to, aClient *from)
163 {
164 Link *lp;
165
166 for(lp = to->user->dccallow; lp; lp = lp->next)
167 if(lp->flags == DCC_LINK_ME && lp->value.cptr == from)
168 return 1;
169 return 0;
170 }
add_dccallow(aClient * sptr,aClient * optr)171 int add_dccallow(aClient *sptr, aClient *optr)
172 {
173 Link *lp;
174 int cnt = 0;
175
176 for (lp = sptr->user->dccallow; lp; lp = lp->next)
177 {
178 if (lp->flags != DCC_LINK_ME)
179 continue;
180 cnt++;
181 if (lp->value.cptr == optr)
182 return 0;
183 }
184
185 if (cnt >= MAXDCCALLOW)
186 {
187 sendto_one(sptr, err_str(ERR_TOOMANYDCC), me.name, sptr->name,
188 optr->name, MAXDCCALLOW);
189 return 0;
190 }
191
192 lp = make_link();
193 lp->value.cptr = optr;
194 lp->flags = DCC_LINK_ME;
195 lp->next = sptr->user->dccallow;
196 sptr->user->dccallow = lp;
197
198 lp = make_link();
199 lp->value.cptr = sptr;
200 lp->flags = DCC_LINK_REMOTE;
201 lp->next = optr->user->dccallow;
202 optr->user->dccallow = lp;
203
204 sendto_one(sptr, rpl_str(RPL_DCCSTATUS), me.name, sptr->name, optr->name, "added to");
205 return 0;
206 }
207
del_dccallow(aClient * sptr,aClient * optr)208 int del_dccallow(aClient *sptr, aClient *optr)
209 {
210 Link **lpp, *lp;
211 int found = 0;
212
213 for (lpp = &(sptr->user->dccallow); *lpp; lpp=&((*lpp)->next))
214 {
215 if ((*lpp)->flags != DCC_LINK_ME)
216 continue;
217 if ((*lpp)->value.cptr == optr)
218 {
219 lp = *lpp;
220 *lpp = lp->next;
221 free_link(lp);
222 found++;
223 break;
224 }
225 }
226 if (!found)
227 {
228 sendto_one(sptr, ":%s %d %s :%s is not in your DCC allow list",
229 me.name, RPL_DCCINFO, sptr->name, optr->name);
230 return 0;
231 }
232
233 for (found = 0, lpp = &(optr->user->dccallow); *lpp; lpp=&((*lpp)->next))
234 {
235 if ((*lpp)->flags != DCC_LINK_REMOTE)
236 continue;
237 if ((*lpp)->value.cptr == sptr)
238 {
239 lp = *lpp;
240 *lpp = lp->next;
241 free_link(lp);
242 found++;
243 break;
244 }
245 }
246 if (!found)
247 sendto_realops("[BUG!] %s was in dccallowme list of %s but not in dccallowrem list!",
248 optr->name, sptr->name);
249
250 sendto_one(sptr, rpl_str(RPL_DCCSTATUS), me.name, sptr->name, optr->name, "removed from");
251
252 return 0;
253 }
254
255 /* restrict channel stuff */
256
channel_canjoin(aClient * sptr,char * name)257 int channel_canjoin(aClient *sptr, char *name)
258 {
259 ConfigItem_deny_channel *p;
260
261 if (IsOper(sptr))
262 return 1;
263 if (IsULine(sptr))
264 return 1;
265 if (!conf_deny_channel)
266 return 1;
267 p = Find_channel_allowed(sptr, name);
268 if (p)
269 {
270 sendto_one(sptr, ":%s NOTICE %s :*** %s",
271 me.name, sptr->name, p->reason);
272 return 0;
273 }
274 return 1;
275 }
276
277 #ifndef _WIN32
278 extern uid_t irc_uid;
279 extern gid_t irc_gid;
280 #endif
281
282 /* irc logs.. */
ircd_log(int flags,char * format,...)283 void ircd_log(int flags, char *format, ...)
284 {
285 static int last_log_file_warning = 0;
286
287 va_list ap;
288 ConfigItem_log *logs;
289 char buf[2048], timebuf[128];
290 int fd;
291 struct stat fstats;
292 int written = 0, write_failure = 0;
293
294 va_start(ap, format);
295 ircvsprintf(buf, format, ap);
296 va_end(ap);
297 snprintf(timebuf, sizeof timebuf, "[%s] - ", myctime(TStime()));
298 RunHook3(HOOKTYPE_LOG, flags, timebuf, buf);
299 strlcat(buf, "\n", sizeof buf);
300
301 for (logs = conf_log; logs; logs = (ConfigItem_log *) logs->next) {
302 #ifdef HAVE_SYSLOG
303 if (!stricmp(logs->file, "syslog") && logs->flags & flags) {
304 syslog(LOG_INFO, "%s", buf);
305 written++;
306 continue;
307 }
308 #endif
309 if (logs->flags & flags)
310 {
311 if (stat(logs->file, &fstats) != -1 && logs->maxsize && fstats.st_size >= logs->maxsize)
312 {
313 #ifndef _WIN32
314 fd = open(logs->file, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR);
315 #else
316 fd = open(logs->file, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE);
317 #endif
318 if (fd == -1)
319 continue;
320 write(fd, "Max file size reached, starting new log file\n", 45);
321 }
322 else {
323 #ifndef _WIN32
324 fd = open(logs->file, O_CREAT|O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR);
325 #else
326 fd = open(logs->file, O_CREAT|O_APPEND|O_WRONLY, S_IREAD|S_IWRITE);
327 #endif
328 if (fd == -1)
329 {
330 if (!loop.ircd_booted)
331 {
332 config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO));
333 } else {
334 if (last_log_file_warning + 300 < TStime())
335 {
336 config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO));
337 last_log_file_warning = TStime();
338 }
339 }
340 write_failure = 1;
341 continue;
342 }
343 }
344 write(fd, timebuf, strlen(timebuf));
345 if (write(fd, buf, strlen(buf)) == strlen(buf))
346 {
347 written++;
348 }
349 else
350 {
351 if (!loop.ircd_booted)
352 {
353 config_status("WARNING: Unable to write to '%s': %s", logs->file, strerror(ERRNO));
354 } else {
355 if (last_log_file_warning + 300 < TStime())
356 {
357 config_status("WARNING: Unable to write to '%s': %s. This warning will not re-appear for at least 5 minutes.", logs->file, strerror(ERRNO));
358 last_log_file_warning = TStime();
359 }
360 }
361 write_failure = 1;
362 }
363 close(fd);
364 #if defined(IRC_USER) && defined(IRC_GROUP)
365 /* Change ownership of the log file to irc user/group so it can still write after the setuid() */
366 if (!loop.ircd_booted)
367 chown(logs->file, irc_uid, irc_gid);
368 #endif
369 }
370 }
371
372 /* If nothing got written at all AND we had a write failure AND we are booting, then exit.
373 * Note that we can't just fail when nothing got written, as we might have been called for
374 * 'tkl' for example, which might not be in our log block.
375 */
376 if (!written && write_failure && !loop.ircd_booted)
377 {
378 config_status("ERROR: Unable to write to any log file. Please check your log { } blocks and file permissions!");
379 #ifdef _WIN32
380 win_error();
381 #endif
382 exit(9);
383 }
384 }
385