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