ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/motd.c
Revision: 5387
Committed: Sun Jan 18 12:43:12 2015 UTC (10 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 13013 byte(s)
Log Message:
- m_gline.c, m_kline.c, motd.c: need to check against client->sockhost as well

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 2916 * Copyright (c) 2000 Kevin L. Mitchell <klmitch@mit.edu>
5 michael 5347 * Copyright (c) 2013-2015 ircd-hybrid development team
6 adx 30 *
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 2 of the License, or
10     * (at your option) 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 michael 4565 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
20 adx 30 * USA
21     */
22    
23 michael 2150 /*! \file motd.c
24     * \brief Message-of-the-day manipulation implementation.
25     * \version $Id$
26     */
27    
28 adx 30 #include "stdinc.h"
29 michael 1011 #include "list.h"
30 adx 30 #include "ircd.h"
31 michael 1309 #include "conf.h"
32 adx 30 #include "send.h"
33     #include "numeric.h"
34     #include "client.h"
35     #include "irc_string.h"
36     #include "memory.h"
37 michael 2150 #include "log.h"
38     #include "motd.h"
39 michael 2167 #include "hostmask.h"
40 adx 30
41 michael 2150
42     /** Global list of messages of the day. */
43     static struct
44 adx 30 {
45 michael 3254 struct Motd *local; /**< Local MOTD. */
46     struct Motd *remote; /**< Remote MOTD. */
47     dlink_list other; /**< MOTDs specified in configuration file. */
48     dlink_list cachelist; /**< List of MotdCache entries. */
49 michael 2150 } MotdList;
50    
51    
52     /*! \brief Create a struct Motd and initialize it.
53 michael 4351 * \param mask Hostmask (or connection class name) to filter on.
54 michael 2150 * \param path Path to MOTD file.
55     */
56     static struct Motd *
57 michael 4351 motd_create(const char *mask, const char *path)
58 michael 2150 {
59 michael 3504 struct Motd *tmp = MyCalloc(sizeof(struct Motd));
60 michael 2150
61 michael 4351 if (EmptyString(mask))
62 michael 2150 tmp->type = MOTD_UNIVERSAL;
63 michael 4351 else if (class_find(mask, 1))
64 michael 2150 tmp->type = MOTD_CLASS;
65     else
66 michael 2167 {
67 michael 4351 switch (parse_netmask(mask, &tmp->address, &tmp->addrbits))
68 michael 2167 {
69     case HM_IPV4:
70 michael 5011 tmp->type = MOTD_IPMASKV4;
71     break;
72     case HM_IPV6:
73     tmp->type = MOTD_IPMASKV6;
74     break;
75     default: /* HM_HOST */
76     tmp->type = MOTD_HOSTMASK;
77     break;
78 michael 2167 }
79     }
80 michael 2150
81 michael 4351 if (mask)
82     tmp->mask = xstrdup(mask);
83 michael 2150
84     tmp->path = xstrdup(path);
85     tmp->maxcount = MOTD_MAXLINES;
86    
87     return tmp;
88 adx 30 }
89    
90 michael 2150 /*! brief\ This function reads a motd out of a file (if needed) and caches it.
91     * If a matching cache entry already exists, reuse it. Otherwise,
92     * allocate and populate a new MotdCache for it.
93     * \param motd Specification for MOTD file.
94     * \return Matching MotdCache entry.
95     */
96     static struct MotdCache *
97     motd_cache(struct Motd *motd)
98 adx 30 {
99 michael 2150 FILE *file = NULL;
100     struct MotdCache *cache = NULL;
101     struct stat sb;
102 michael 3254 char line[MOTD_LINESIZE + 2]; /* +2 for \r\n */
103 michael 2194 char *tmp = NULL;
104 michael 2164 unsigned int i = 0;
105 michael 4815 dlink_node *node = NULL;
106 adx 30
107 michael 2150 assert(motd);
108     assert(motd->path);
109 adx 30
110 michael 2150 if (motd->cache)
111     return motd->cache;
112 adx 30
113 michael 4348 /* Try to find it in the list of cached files */
114 michael 4815 DLINK_FOREACH(node, MotdList.cachelist.head)
115 michael 2150 {
116 michael 4815 cache = node->data;
117 adx 30
118 michael 2150 if (!strcmp(cache->path, motd->path) && cache->maxcount == motd->maxcount)
119     {
120 michael 4348 cache->ref++; /* Increase reference count */
121     motd->cache = cache; /* Remember cache */
122 michael 3254 return motd->cache; /* Return it */
123 michael 2150 }
124     }
125    
126 michael 3254 /* Need the file's modification time */
127 michael 2190 if (stat(motd->path, &sb) == -1)
128 adx 30 {
129 michael 2190 ilog(LOG_TYPE_IRCD, "Couldn't stat \"%s\": %s", motd->path,
130 michael 2150 strerror(errno));
131     return 0;
132     }
133 adx 30
134 michael 3254 /* Gotta read in the file, now */
135 michael 2190 if ((file = fopen(motd->path, "r")) == NULL)
136 michael 2150 {
137 michael 2190 ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", motd->path,
138     strerror(errno));
139 michael 2150 return 0;
140     }
141 adx 30
142 michael 2150 /* Ok, allocate a structure; we'll realloc later to trim memory */
143 michael 3504 cache = MyCalloc(sizeof(struct MotdCache) + (MOTD_LINESIZE * MOTD_MAXLINES));
144 michael 2150 cache->ref = 1;
145     cache->path = xstrdup(motd->path);
146     cache->maxcount = motd->maxcount;
147 michael 4348 cache->modtime = *localtime((const time_t *)&sb.st_mtime); /* Store modtime */
148 adx 30
149 michael 2150 while (cache->count < cache->maxcount && fgets(line, sizeof(line), file))
150     {
151 michael 3254 /* Copy over line, stopping when we overflow or hit line end */
152 michael 2194 for (tmp = line, i = 0; i < (MOTD_LINESIZE - 1) && *tmp && *tmp != '\r' && *tmp != '\n'; ++tmp, ++i)
153 michael 2150 cache->motd[cache->count][i] = *tmp;
154     cache->motd[cache->count][i] = '\0';
155 adx 30
156 michael 2150 cache->count++;
157 adx 30 }
158    
159 michael 3254 fclose(file); /* Close the file */
160 michael 2150
161 michael 3254 /* Trim memory usage a little */
162 michael 3504 motd->cache = MyCalloc(sizeof(struct MotdCache) +
163 michael 2410 (MOTD_LINESIZE * cache->count));
164 michael 2150 memcpy(motd->cache, cache, sizeof(struct MotdCache) +
165 michael 2410 (MOTD_LINESIZE * cache->count));
166 michael 2150 MyFree(cache);
167    
168 michael 4348 /* Now link it in */
169 michael 2150 dlinkAdd(motd->cache, &motd->cache->node, &MotdList.cachelist);
170    
171     return motd->cache;
172 adx 30 }
173    
174 michael 2150 /*! \brief Clear and dereference the Motd::cache element of \a motd.
175     * If the MotdCache::ref count goes to zero, free it.
176     * \param motd MOTD to uncache.
177 adx 30 */
178 michael 2150 static void
179     motd_decache(struct Motd *motd)
180 adx 30 {
181 michael 2150 struct MotdCache *cache = NULL;
182 adx 30
183 michael 2150 assert(motd);
184 adx 30
185 michael 3254 if ((cache = motd->cache) == NULL) /* We can be called for records with no cache */
186 michael 2150 return;
187 adx 30
188 michael 3254 motd->cache = NULL; /* Zero the cache */
189 adx 30
190 michael 4348 if (--cache->ref == 0) /* Reduce reference count */
191 adx 30 {
192 michael 2150 dlinkDelete(&cache->node, &MotdList.cachelist);
193 michael 4348 MyFree(cache->path); /* Free path info */
194     MyFree(cache); /* Very simple for a reason */
195 adx 30 }
196 michael 2150 }
197 adx 30
198 michael 2150 /*! \brief Deallocate a MOTD structure.
199     * If it has cached content, uncache it.
200     * \param motd MOTD to destroy.
201     */
202     static void
203     motd_destroy(struct Motd *motd)
204     {
205     assert(motd);
206 adx 30
207 michael 3254 if (motd->cache) /* Drop the cache */
208 michael 2150 motd_decache(motd);
209 adx 30
210 michael 3254 MyFree(motd->path); /* We always must have a path */
211 michael 4351 MyFree(motd->mask);
212 michael 2150 MyFree(motd);
213     }
214 adx 30
215 michael 2150 /*! \brief Find the first matching MOTD block for a user.
216     * If the user is remote, always use remote MOTD.
217     * Otherwise, if there is a hostmask- or class-based MOTD that matches
218     * the user, use it.
219     * Otherwise, use the local MOTD.
220     * \param client_p Client to find MOTD for.
221     * \return Pointer to first matching MOTD for the client.
222     */
223     static struct Motd *
224 michael 2874 motd_lookup(const struct Client *client_p)
225 michael 2150 {
226 michael 4815 dlink_node *node = NULL;
227 michael 2150 const struct ClassItem *class = NULL;
228 adx 30
229 michael 2150 assert(client_p);
230 adx 30
231 michael 3292 if (!MyConnect(client_p)) /* Not my user, always return remote motd */
232 michael 2150 return MotdList.remote;
233 adx 30
234 michael 4588 class = get_class_ptr(&client_p->connection->confs);
235 michael 2150 assert(class);
236 adx 30
237 michael 3254 /* Check the motd blocks first */
238 michael 4815 DLINK_FOREACH(node, MotdList.other.head)
239 michael 2150 {
240 michael 4815 struct Motd *motd = node->data;
241 adx 30
242 michael 2150 switch (motd->type)
243 adx 30 {
244 michael 2150 case MOTD_CLASS:
245 michael 4351 if (!match(motd->mask, class->name))
246 michael 2150 return motd;
247 michael 2167 break;
248 michael 2150 case MOTD_HOSTMASK:
249 michael 5387 if (!match(motd->mask, client_p->host) || !match(motd->mask, client_p->sockhost))
250 michael 2150 return motd;
251 michael 2167 break;
252     case MOTD_IPMASKV4:
253 michael 4588 if (client_p->connection->aftype == AF_INET)
254     if (match_ipv4(&client_p->connection->ip, &motd->address, motd->addrbits))
255 michael 2167 return motd;
256     break;
257     case MOTD_IPMASKV6:
258 michael 4588 if (client_p->connection->aftype == AF_INET6)
259     if (match_ipv6(&client_p->connection->ip, &motd->address, motd->addrbits))
260 michael 2167 return motd;
261     break;
262 michael 2150 default: break;
263 adx 30 }
264     }
265    
266 michael 3254 return MotdList.local; /* Ok, return the default motd */
267 adx 30 }
268    
269 michael 2150 /*! \brief Send the content of a MotdCache to a user.
270     * If \a cache is NULL, simply send ERR_NOMOTD to the client.
271     * \param source_p Client to send MOTD to.
272     * \param cache MOTD body to send to client.
273 adx 30 */
274 michael 2150 static void
275     motd_forward(struct Client *source_p, const struct MotdCache *cache)
276     {
277 michael 3254 if (!cache) /* No motd to send */
278 michael 2150 {
279 michael 3109 sendto_one_numeric(source_p, &me, ERR_NOMOTD);
280 michael 2150 return;
281     }
282    
283 michael 3254 /* Send the motd */
284 michael 3109 sendto_one_numeric(source_p, &me, RPL_MOTDSTART, me.name);
285 michael 2150
286 michael 3235 for (unsigned int i = 0; i < cache->count; ++i)
287 michael 3109 sendto_one_numeric(source_p, &me, RPL_MOTD, cache->motd[i]);
288 michael 4890
289 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFMOTD);
290 michael 2150 }
291    
292     /*! \brief Find the MOTD for a client and send it.
293     * \param client_p Client being greeted.
294     */
295     void
296     motd_send(struct Client *client_p)
297 adx 30 {
298 michael 2150 assert(client_p);
299 adx 30
300 michael 2150 motd_forward(client_p, motd_cache(motd_lookup(client_p)));
301 adx 30 }
302    
303 michael 2150 /*! \brief Send the signon MOTD to a user.
304 michael 3254 * If general::short_motd is true and a matching MOTD exists for the
305     * user, direct the client to type /MOTD to read it. Otherwise, call
306 michael 2150 * motd_forward() for the user.
307     * \param source_p Client that has just connected.
308 adx 30 */
309     void
310 michael 2150 motd_signon(struct Client *source_p)
311 adx 30 {
312 michael 2150 const struct MotdCache *cache = motd_cache(motd_lookup(source_p));
313 adx 30
314 michael 4340 if (!ConfigGeneral.short_motd || !cache)
315 michael 2150 motd_forward(source_p, cache);
316     else
317 adx 30 {
318 michael 3110 sendto_one_notice(source_p, &me, ":*** Notice -- motd was last changed at %d/%d/%d %d:%02d",
319     cache->modtime.tm_year + 1900,
320     cache->modtime.tm_mon + 1,
321     cache->modtime.tm_mday,
322     cache->modtime.tm_hour,
323     cache->modtime.tm_min);
324     sendto_one_notice(source_p, &me, ":*** Notice -- Please read the motd if you haven't read it");
325 michael 3109 sendto_one_numeric(source_p, &me, RPL_MOTDSTART, me.name);
326 michael 4890 sendto_one_numeric(source_p, &me, RPL_MOTD, "*** This is the short motd ***");
327 michael 3109 sendto_one_numeric(source_p, &me, RPL_ENDOFMOTD);
328 adx 30 }
329 michael 2150 }
330    
331     /*! \brief Clear all cached MOTD bodies.
332     * The local and remote MOTDs are re-cached immediately.
333     */
334     void
335     motd_recache(void)
336     {
337 michael 4815 dlink_node *node = NULL;
338 michael 2150
339 michael 3254 motd_decache(MotdList.local); /* Decache local and remote MOTDs */
340 michael 2150 motd_decache(MotdList.remote);
341    
342 michael 4815 DLINK_FOREACH(node, MotdList.other.head) /* Now all the others */
343     motd_decache(node->data);
344 michael 2150
345 michael 4348 /* Now recache local and remote MOTDs */
346 michael 2150 motd_cache(MotdList.local);
347     motd_cache(MotdList.remote);
348     }
349    
350     /*! \brief Re-cache the local and remote MOTDs.
351     * If they already exist, they are deallocated first.
352     */
353     void
354     motd_init(void)
355     {
356 michael 4348 if (MotdList.local) /* Destroy old local MOTD */
357 michael 2150 motd_destroy(MotdList.local);
358    
359 michael 2203 MotdList.local = motd_create(NULL, MPATH);
360 michael 4348 motd_cache(MotdList.local); /* Initialize local MOTD and cache it */
361 michael 2150
362 michael 4348 if (MotdList.remote) /* Destroy old remote MOTD */
363 michael 2150 motd_destroy(MotdList.remote);
364    
365 michael 2203 MotdList.remote = motd_create(NULL, MPATH);
366 michael 4348 motd_cache(MotdList.remote); /* Initialize remote MOTD and cache it */
367 michael 2150 }
368    
369     /* \brief Add a new MOTD.
370 michael 4351 * \param mask Hostmask (or connection class name) to send this to.
371 michael 2150 * \param path Pathname of file to send.
372     */
373     void
374 michael 4351 motd_add(const char *mask, const char *path)
375 michael 2150 {
376 michael 4351 struct Motd *motd = motd_create(mask, path); /* Create the motd */
377 michael 2150
378     dlinkAdd(motd, &motd->node, &MotdList.other);
379     }
380    
381     /*! \brief Clear out all MOTDs.
382     * Compared to motd_recache(), this destroys all hostmask- or
383     * class-based MOTDs rather than simply uncaching them.
384     * Re-cache the local and remote MOTDs.
385     */
386     void
387     motd_clear(void)
388     {
389 michael 4815 dlink_node *node = NULL, *node_next = NULL;
390 michael 2150
391 michael 3254 motd_decache(MotdList.local); /* Decache local and remote MOTDs */
392 michael 2150 motd_decache(MotdList.remote);
393    
394 michael 4815 DLINK_FOREACH_SAFE(node, node_next, MotdList.other.head) /* Destroy other MOTDs */
395 michael 2193 {
396 michael 4815 dlinkDelete(node, &MotdList.other);
397     motd_destroy(node->data);
398 michael 2193 }
399 michael 2150
400 michael 4348 /* Now recache local and remote MOTDs */
401 michael 2150 motd_cache(MotdList.local);
402     motd_cache(MotdList.remote);
403     }
404    
405     /*! \brief Report list of non-default MOTDs.
406     * \param source_p Client requesting statistics.
407     */
408     void
409 michael 4479 motd_report(struct Client *source_p, int parc, char *parv[])
410 michael 2150 {
411 michael 4815 const dlink_node *node = NULL;
412 michael 2150
413 michael 4815 DLINK_FOREACH(node, MotdList.other.head)
414 adx 30 {
415 michael 4815 const struct Motd *motd = node->data;
416 michael 2150
417 michael 3109 sendto_one_numeric(source_p, &me, RPL_STATSTLINE,
418 michael 4351 motd->mask, motd->path);
419 adx 30 }
420     }
421    
422 michael 2150 /*! \brief Report MOTD memory usage to a client.
423     * \param source_p Client requesting memory usage.
424 adx 30 */
425     void
426 michael 2150 motd_memory_count(struct Client *source_p)
427 adx 30 {
428 michael 4815 const dlink_node *node = NULL;
429 michael 4348 unsigned int mt = 0; /* Motd count */
430     unsigned int mtc = 0; /* Motd cache count */
431     size_t mtm = 0; /* Memory consumed by motd */
432     size_t mtcm = 0; /* Memory consumed by motd cache */
433 adx 30
434 michael 2150 if (MotdList.local)
435     {
436     mt++;
437     mtm += sizeof(struct Motd);
438     mtm += MotdList.local->path ? (strlen(MotdList.local->path) + 1) : 0;
439     }
440 adx 30
441 michael 2150 if (MotdList.remote)
442 adx 30 {
443 michael 2150 mt++;
444     mtm += sizeof(struct Motd);
445     mtm += MotdList.remote->path ? (strlen(MotdList.remote->path) + 1) : 0;
446     }
447    
448 michael 4815 DLINK_FOREACH(node, MotdList.other.head)
449 michael 2150 {
450 michael 4815 const struct Motd *motd = node->data;
451 michael 2150
452     mt++;
453     mtm += sizeof(struct Motd);
454     mtm += motd->path ? (strlen(motd->path) + 1) : 0;
455     }
456    
457 michael 4815 DLINK_FOREACH(node, MotdList.cachelist.head)
458 michael 2150 {
459 michael 4815 const struct MotdCache *cache = node->data;
460 michael 2150
461     mtc++;
462     mtcm += sizeof(struct MotdCache) + (MOTD_LINESIZE * (cache->count - 1));
463     }
464    
465 michael 3589 sendto_one_numeric(source_p, &me, RPL_STATSDEBUG|SND_EXPLICIT,
466     "z :Motds %u(%u) Cache %u(%u)",
467     mt, mtm, mtc, mtcm);
468 adx 30 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision