ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/modules/m_gline.c
Revision: 1243
Committed: Fri Sep 30 10:47:53 2011 UTC (12 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 20976 byte(s)
Log Message:
- move content of msg.h, ircd_handler.h and handlers.h into parse.h and
  remove headers accordingly
- killed common.h
- remove m_killhost.c and m_flags.c from contrib/
- sort out unused header includes here and there

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 *
4 * Copyright (C) 2002 by the past and present ircd coders, and others.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22 /*! \file m_gline.c
23 * \brief Includes required functions for processing the GLINE command.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "s_gline.h"
30 #include "channel.h"
31 #include "client.h"
32 #include "irc_string.h"
33 #include "sprintf_irc.h"
34 #include "ircd.h"
35 #include "hostmask.h"
36 #include "numeric.h"
37 #include "s_bsd.h"
38 #include "s_conf.h"
39 #include "s_misc.h"
40 #include "send.h"
41 #include "fileio.h"
42 #include "s_serv.h"
43 #include "hash.h"
44 #include "parse.h"
45 #include "modules.h"
46 #include "s_log.h"
47
48 #define GLINE_NOT_PLACED 0
49 #define GLINE_ALREADY_VOTED -1
50 #define GLINE_PLACED 1
51
52
53 /*! \brief Adds a GLINE to the configuration subsystem.
54 *
55 * \param source_p Operator requesting gline
56 * \param user Username covered by the gline
57 * \param host Hostname covered by the gline
58 * \param reason Reason for the gline
59 */
60 static void
61 set_local_gline(const struct Client *source_p, const char *user,
62 const char *host, const char *reason)
63 {
64 char buffer[IRCD_BUFSIZE];
65 struct ConfItem *conf;
66 struct AccessItem *aconf;
67
68
69 conf = make_conf_item(GLINE_TYPE);
70 aconf = map_to_conf(conf);
71
72 snprintf(buffer, sizeof(buffer), "%s (%s)", reason, smalldate(CurrentTime));
73 DupString(aconf->reason, buffer);
74 DupString(aconf->user, user);
75 DupString(aconf->host, host);
76
77 aconf->hold = CurrentTime + ConfigFileEntry.gline_time;
78 add_temp_line(conf);
79
80 sendto_realops_flags(UMODE_ALL, L_ALL,
81 "%s added G-Line for [%s@%s] [%s]",
82 get_oper_name(source_p),
83 aconf->user, aconf->host, aconf->reason);
84 ilog(L_TRACE, "%s added G-Line for [%s@%s] [%s]",
85 get_oper_name(source_p), aconf->user, aconf->host, aconf->reason);
86 log_oper_action(LOG_GLINE_TYPE, source_p, "[%s@%s] [%s]\n",
87 aconf->user, aconf->host, aconf->reason);
88 /* Now, activate gline against current online clients */
89 rehashed_klines = 1;
90 }
91
92 /*! \brief Removes a GLINE from the configuration subsystem.
93 *
94 * \param user Username covered by the gline
95 * \param host Hostname covered by the gline
96 */
97 static int
98 remove_gline_match(const char *user, const char *host)
99 {
100 struct AccessItem *aconf;
101 dlink_node *ptr = NULL;
102 struct irc_ssaddr addr, caddr;
103 int nm_t, cnm_t, bits, cbits;
104
105 nm_t = parse_netmask(host, &addr, &bits);
106
107 DLINK_FOREACH(ptr, temporary_glines.head)
108 {
109 aconf = map_to_conf(ptr->data);
110 cnm_t = parse_netmask(aconf->host, &caddr, &cbits);
111
112 if (cnm_t != nm_t || irccmp(user, aconf->user))
113 continue;
114
115 if ((nm_t == HM_HOST && !irccmp(aconf->host, host)) ||
116 (nm_t == HM_IPV4 && bits == cbits && match_ipv4(&addr, &caddr, bits))
117 #ifdef IPV6
118 || (nm_t == HM_IPV6 && bits == cbits && match_ipv6(&addr, &caddr, bits))
119 #endif
120 )
121 {
122 dlinkDelete(ptr, &temporary_glines);
123 delete_one_address_conf(aconf->host, aconf);
124 return 1;
125 }
126 }
127
128 return 0;
129 }
130
131 /*! \brief This function is called once a majority of opers have agreed on a
132 * GLINE/GUNGLINE, and it can be placed. The information about an
133 * operator being passed to us happens to be the operator who pushed us
134 * over the "majority" level needed. See check_majority() for more
135 * information.
136 *
137 * \param source_p Operator requesting gline
138 * \param user Username covered by the gline
139 * \param host Hostname covered by the gline
140 * \param reason Reason for the gline
141 * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
142 * GLINE_PENDING_DEL_TYPE
143 */
144 static void
145 add_new_majority(const struct Client *source_p, const char *user,
146 const char *host, const char *reason, const unsigned int type)
147 {
148 struct gline_pending *pending = MyMalloc(sizeof(struct gline_pending));
149
150 strlcpy(pending->vote_1.oper_nick, source_p->name, sizeof(pending->vote_1.oper_nick));
151 strlcpy(pending->vote_1.oper_user, source_p->username, sizeof(pending->vote_1.oper_user));
152 strlcpy(pending->vote_1.oper_host, source_p->host, sizeof(pending->vote_1.oper_host));
153 strlcpy(pending->vote_1.oper_server, source_p->servptr->name, sizeof(pending->vote_1.oper_server));
154
155 strlcpy(pending->user, user, sizeof(pending->user));
156 strlcpy(pending->host, host, sizeof(pending->host));
157 strlcpy(pending->vote_1.reason, reason, sizeof(pending->vote_1.reason));
158
159 pending->last_gline_time = CurrentTime;
160 pending->vote_1.time_request = CurrentTime;
161
162 dlinkAdd(pending, &pending->node, &pending_glines[type]);
163 }
164
165 /*! \brief See if there is a majority agreement on a GLINE on the given user.
166 * There must be at least 3 different opers agreeing on this
167 * GLINE/GUNGLINE
168 *
169 * \param source_p Operator requesting gline
170 * \param user Username covered by the gline
171 * \param host Hostname covered by the gline
172 * \param reason Reason for the gline
173 * \param type Valid values are either GLINE_PENDING_ADD_TYPE, or
174 * GLINE_PENDING_DEL_TYPE
175 *
176 * \return
177 * - GLINE_ALREADY_VOTED returned if oper/server has already voted
178 * - GLINE_PLACED returned if this triggers a gline
179 * - GLINE_NOT_PLACED returned if not triggered
180 */
181 static int
182 check_majority(const struct Client *source_p, const char *user,
183 const char *host, const char *reason, const int type)
184 {
185 dlink_node *dn_ptr = NULL;
186
187 cleanup_glines(NULL);
188
189 /* if its already glined, why bother? :) -- fl_ */
190 if ((type == GLINE_PENDING_ADD_TYPE) && find_is_glined(host, user))
191 return GLINE_NOT_PLACED;
192
193 DLINK_FOREACH(dn_ptr, pending_glines[type].head)
194 {
195 struct gline_pending *gp_ptr = dn_ptr->data;
196
197 if (irccmp(gp_ptr->user, user) ||
198 irccmp(gp_ptr->host, host))
199 continue;
200
201 if ((!irccmp(gp_ptr->vote_1.oper_user, source_p->username) &&
202 !irccmp(gp_ptr->vote_1.oper_host, source_p->host)) ||
203 !irccmp(gp_ptr->vote_1.oper_server, source_p->servptr->name))
204 return GLINE_ALREADY_VOTED;
205
206 if (gp_ptr->vote_2.oper_user[0] != '\0')
207 {
208 /* if two other opers on two different servers have voted yes */
209 if ((!irccmp(gp_ptr->vote_2.oper_user, source_p->username) &&
210 !irccmp(gp_ptr->vote_2.oper_host, source_p->host)) ||
211 !irccmp(gp_ptr->vote_2.oper_server, source_p->servptr->name))
212 return GLINE_ALREADY_VOTED;
213
214 if (type == GLINE_PENDING_DEL_TYPE)
215 {
216 if (remove_gline_match(user, host))
217 {
218 sendto_realops_flags(UMODE_ALL, L_ALL,
219 "%s has removed the G-Line for: [%s@%s]",
220 get_oper_name(source_p), user, host);
221 ilog(L_NOTICE, "%s removed G-Line for [%s@%s]",
222 get_oper_name(source_p), user, host);
223 }
224 }
225 else
226 /* trigger the gline using the original reason --fl */
227 set_local_gline(source_p, user, host, gp_ptr->vote_1.reason);
228
229 cleanup_glines(gp_ptr);
230 return GLINE_PLACED;
231 }
232
233 strlcpy(gp_ptr->vote_2.oper_nick, source_p->name,
234 sizeof(gp_ptr->vote_2.oper_nick));
235 strlcpy(gp_ptr->vote_2.oper_user, source_p->username,
236 sizeof(gp_ptr->vote_2.oper_user));
237 strlcpy(gp_ptr->vote_2.oper_host, source_p->host,
238 sizeof(gp_ptr->vote_2.oper_host));
239 strlcpy(gp_ptr->vote_2.reason, reason,
240 sizeof(gp_ptr->vote_2.reason));
241 strlcpy(gp_ptr->vote_2.oper_server, source_p->servptr->name,
242 sizeof(gp_ptr->vote_2.oper_server));
243 gp_ptr->last_gline_time = CurrentTime;
244 gp_ptr->vote_2.time_request = CurrentTime;
245 return GLINE_NOT_PLACED;
246 }
247
248 /*
249 * Didn't find this user@host gline in pending gline list
250 * so add it.
251 */
252 add_new_majority(source_p, user, host, reason, type);
253 return GLINE_NOT_PLACED;
254 }
255
256 static void
257 do_sgline(struct Client *source_p, int parc, char *parv[], int prop)
258 {
259 const char *reason = NULL; /* reason for "victims" demise */
260 char *user = NULL;
261 char *host = NULL; /* user and host of GLINE "victim" */
262 int var_offset = 0, logged = 0;
263 dlink_node *ptr;
264 struct Client *target_p = NULL;
265
266 switch (parc)
267 {
268 case 4: /* hyb-7 style */
269 if (!IsClient(source_p))
270 return;
271 break;
272 case 8: /* hyb-6 style */
273 if (!IsServer(source_p))
274 return;
275 target_p = find_person(source_p->from, parv[1]);
276 if (target_p == NULL || target_p->servptr != source_p)
277 return;
278 source_p = target_p, var_offset = 4;
279 break;
280 default:
281 return;
282 }
283
284 assert(source_p->servptr != NULL);
285
286 user = parv[++var_offset];
287 host = parv[++var_offset];
288 reason = parv[++var_offset];
289
290 var_offset = 0;
291
292 DLINK_FOREACH(ptr, gdeny_items.head)
293 {
294 struct ConfItem *conf = ptr->data;
295 struct AccessItem *aconf = map_to_conf(conf);
296
297 if (match(conf->name, source_p->servptr->name) &&
298 match(aconf->user, source_p->username) &&
299 match(aconf->host, source_p->host))
300 {
301 var_offset = aconf->flags;
302 break;
303 }
304 }
305
306 if (prop && !(var_offset & GDENY_BLOCK))
307 {
308 sendto_server(source_p->from, NULL, CAP_GLN, NOCAPS,
309 ":%s GLINE %s %s :%s",
310 source_p->name, user, host, reason);
311 /* hyb-6 version to the rest */
312 sendto_server(source_p->from, NULL, NOCAPS, CAP_GLN,
313 ":%s GLINE %s %s %s %s %s %s :%s",
314 source_p->servptr->name,
315 source_p->name, source_p->username, source_p->host,
316 source_p->servptr->name,
317 user, host, reason);
318 }
319 else if (ConfigFileEntry.gline_logging & GDENY_BLOCK && ServerInfo.hub)
320 {
321 sendto_realops_flags(UMODE_ALL, L_ALL, "Blocked G-Line %s requested on [%s@%s] [%s]",
322 get_oper_name(source_p), user, host, reason);
323 ilog(L_TRACE, "Blocked G-Line %s requested on [%s@%s] [%s]",
324 get_oper_name(source_p), user, host, reason);
325 logged = 1;
326 }
327
328 if (var_offset & GDENY_REJECT)
329 {
330 if (ConfigFileEntry.gline_logging & GDENY_REJECT && !logged)
331 {
332 sendto_realops_flags(UMODE_ALL, L_ALL, "Rejected G-Line %s requested on [%s@%s] [%s]",
333 get_oper_name(source_p), user, host, reason);
334 ilog(L_TRACE, "Rejected G-Line %s requested on [%s@%s] [%s]",
335 get_oper_name(source_p), user, host, reason);
336 }
337
338 return;
339 }
340
341 if (ConfigFileEntry.glines)
342 {
343 if (!valid_wild_card(source_p, 1, 2, user, host))
344 return;
345
346 if (IsClient(source_p))
347 {
348 const char *p = NULL;
349
350 if ((p = strchr(host, '/')))
351 {
352 int bitlen = strtol(++p, NULL, 10);
353 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
354 ConfigFileEntry.gline_min_cidr;
355
356 if (bitlen < min_bitlen)
357 {
358 sendto_realops_flags(UMODE_ALL, L_ALL, "%s!%s@%s on %s is requesting "
359 "a GLINE with a CIDR mask < %d for [%s@%s] [%s]",
360 source_p->name, source_p->username, source_p->host,
361 source_p->servptr->name, min_bitlen, user, host, reason);
362 return;
363 }
364 }
365 }
366
367 /* If at least 3 opers agree this user should be G lined then do it */
368 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
369 GLINE_ALREADY_VOTED)
370 {
371 sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
372 return;
373 }
374
375 sendto_realops_flags(UMODE_ALL, L_ALL,
376 "%s requesting G-Line for [%s@%s] [%s]",
377 get_oper_name(source_p),
378 user, host, reason);
379 ilog(L_TRACE, "#gline for %s@%s [%s] requested by %s",
380 user, host, reason, get_oper_name(source_p));
381 }
382 }
383
384
385 /*! \brief GLINE command handler (called by operators)
386 *
387 * \param client_p Pointer to allocated Client struct with physical connection
388 * to this server, i.e. with an open socket connected.
389 * \param source_p Pointer to allocated Client struct from which the message
390 * originally comes from. This can be a local or remote client.
391 * \param parc Integer holding the number of supplied arguments.
392 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
393 * pointers.
394 * \note Valid arguments for this command are:
395 * - parv[0] = sender prefix
396 * - parv[1] = user\@host mask
397 * - parv[2] = reason
398 */
399 static void
400 mo_gline(struct Client *client_p, struct Client *source_p,
401 int parc, char *parv[])
402 {
403 char *user = NULL;
404 char *host = NULL;
405 char *reason = NULL;
406 char *p;
407
408 if (!ConfigFileEntry.glines)
409 {
410 sendto_one(source_p, ":%s NOTICE %s :GLINE disabled",
411 me.name, source_p->name);
412 return;
413 }
414
415 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
416 {
417 sendto_one(source_p, form_str(ERR_NOPRIVS),
418 me.name, source_p->name, "gline");
419 return;
420 }
421
422 if (parse_aline("GLINE", source_p, parc, parv, AWILD,
423 &user, &host, NULL, NULL, &reason) < 0)
424 return;
425
426 if ((p = strchr(host, '/')) != NULL)
427 {
428 int bitlen = strtol(++p, NULL, 10);
429 int min_bitlen = strchr(host, ':') ? ConfigFileEntry.gline_min_cidr6 :
430 ConfigFileEntry.gline_min_cidr;
431 if (bitlen < min_bitlen)
432 {
433 sendto_one(source_p, ":%s NOTICE %s :Cannot set G-Lines with CIDR length < %d",
434 me.name, source_p->name, min_bitlen);
435 return;
436 }
437 }
438
439 /* If at least 3 opers agree this user should be G lined then do it */
440 if (check_majority(source_p, user, host, reason, GLINE_PENDING_ADD_TYPE) ==
441 GLINE_ALREADY_VOTED)
442 {
443 sendto_one(source_p,
444 ":%s NOTICE %s :This server or oper has already voted",
445 me.name, source_p->name);
446 return;
447 }
448
449 /*
450 * call these two functions first so the 'requesting' notice always comes
451 * before the 'has triggered' notice. -bill
452 */
453 sendto_realops_flags(UMODE_ALL, L_ALL,
454 "%s requesting G-Line for [%s@%s] [%s]",
455 get_oper_name(source_p),
456 user, host, reason);
457 ilog(L_TRACE, "#gline for %s@%s [%s] requested by %s!%s@%s",
458 user, host, reason, source_p->name, source_p->username,
459 source_p->host);
460
461 /* 4 param version for hyb-7 servers */
462 sendto_server(NULL, NULL, CAP_GLN|CAP_TS6, NOCAPS,
463 ":%s GLINE %s %s :%s",
464 ID(source_p), user, host, reason);
465 sendto_server(NULL, NULL, CAP_GLN, CAP_TS6,
466 ":%s GLINE %s %s :%s",
467 source_p->name, user, host, reason);
468
469 /* 8 param for hyb-6 */
470 sendto_server(NULL, NULL, CAP_TS6, CAP_GLN,
471 ":%s GLINE %s %s %s %s %s %s :%s",
472 ID(&me),
473 ID(source_p), source_p->username,
474 source_p->host, source_p->servptr->name, user, host,
475 reason);
476 sendto_server(NULL, NULL, NOCAPS, CAP_GLN|CAP_TS6,
477 ":%s GLINE %s %s %s %s %s %s :%s",
478 me.name, source_p->name, source_p->username,
479 source_p->host, source_p->servptr->name, user, host,
480 reason);
481 }
482
483 /* ms_gline()
484 * me_gline()
485 * do_sgline()
486 *
487 * inputs - The usual for a m_ function
488 * output -
489 * side effects -
490 *
491 * Place a G line if 3 opers agree on the identical user@host
492 *
493 * Allow this server to pass along GLINE if received and
494 * GLINES is not defined.
495 *
496 * ENCAP'd GLINES are propagated by encap code.
497 */
498
499 static void
500 ms_gline(struct Client *client_p, struct Client *source_p,
501 int parc, char *parv[])
502 {
503 do_sgline(source_p, parc, parv, 1);
504 }
505
506 static void
507 me_gline(struct Client *client_p, struct Client *source_p,
508 int parc, char *parv[])
509 {
510 do_sgline(source_p, parc, parv, 0);
511 }
512
513 static void
514 do_sungline(struct Client *source_p, const char *user,
515 const char *host, const char *reason, int prop)
516 {
517 assert(source_p->servptr != NULL);
518
519 sendto_realops_flags(UMODE_ALL, L_ALL,
520 "%s requesting UNG-Line for [%s@%s] [%s]",
521 get_oper_name(source_p), user, host, reason);
522 ilog(L_TRACE, "#ungline for %s@%s [%s] requested by %s",
523 user, host, reason, get_oper_name(source_p));
524
525 /* If at least 3 opers agree this user should be un G lined then do it */
526 if (check_majority(source_p, user, host, reason, GLINE_PENDING_DEL_TYPE) ==
527 GLINE_ALREADY_VOTED)
528 sendto_realops_flags(UMODE_ALL, L_ALL, "oper or server has already voted");
529
530 if (prop)
531 {
532 sendto_server(source_p->from, NULL, CAP_ENCAP|CAP_TS6, NOCAPS,
533 ":%s ENCAP * GUNGLINE %s %s :%s",
534 ID(source_p), user, host, reason);
535 sendto_server(source_p->from, NULL, CAP_ENCAP, CAP_TS6,
536 ":%s ENCAP * GUNGLINE %s %s :%s",
537 source_p->name, user, host, reason);
538 }
539 }
540
541 /*! \brief GUNGLINE command handler (called in response to an encapsulated
542 * GUNGLINE command)
543 *
544 * \param client_p Pointer to allocated Client struct with physical connection
545 * to this server, i.e. with an open socket connected.
546 * \param source_p Pointer to allocated Client struct from which the message
547 * originally comes from. This can be a local or remote client.
548 * \param parc Integer holding the number of supplied arguments.
549 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
550 * pointers.
551 * \note Valid arguments for this command are:
552 * - parv[0] = sender prefix
553 * - parv[1] = username
554 * - parv[2] = hostname
555 * - parv[3] = reason
556 */
557 static void
558 me_gungline(struct Client *client_p, struct Client *source_p,
559 int parc, char *parv[])
560 {
561 if (ConfigFileEntry.glines)
562 do_sungline(source_p, parv[1], parv[2], parv[3], 0);
563 }
564
565 /*! \brief GUNGLINE command handler (called by operators)
566 *
567 * \param client_p Pointer to allocated Client struct with physical connection
568 * to this server, i.e. with an open socket connected.
569 * \param source_p Pointer to allocated Client struct from which the message
570 * originally comes from. This can be a local or remote client.
571 * \param parc Integer holding the number of supplied arguments.
572 * \param parv Argument vector where parv[0] .. parv[parc-1] are non-NULL
573 * pointers.
574 * \note Valid arguments for this command are:
575 * - parv[0] = sender prefix
576 * - parv[1] = user\@host mask
577 * - parv[2] = reason
578 */
579 static void
580 mo_gungline(struct Client *client_p, struct Client *source_p,
581 int parc, char *parv[])
582 {
583 char *user = NULL;
584 char *host = NULL;
585 char *reason = NULL;
586
587 if (!ConfigFileEntry.glines)
588 {
589 sendto_one(source_p, ":%s NOTICE %s :GUNGLINE disabled",
590 me.name, source_p->name);
591 return;
592 }
593
594 if (!HasOFlag(source_p, OPER_FLAG_GLINE))
595 {
596 sendto_one(source_p, form_str(ERR_NOPRIVS),
597 me.name, source_p->name, "gungline");
598 return;
599 }
600
601 if (parse_aline("GUNGLINE", source_p, parc, parv, 0, &user,
602 &host, NULL, NULL, &reason) < 0)
603 return;
604
605 do_sungline(source_p, user, host, reason, 1);
606 }
607
608 /*
609 * gline enforces 3 parameters to force operator to give a reason
610 * a gline is not valid with "No reason"
611 * -db
612 */
613 static struct Message gline_msgtab = {
614 "GLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
615 { m_unregistered, m_not_oper, ms_gline, me_gline, mo_gline, m_ignore }
616 };
617
618 static struct Message ungline_msgtab = {
619 "GUNGLINE", 0, 0, 3, MAXPARA, MFLG_SLOW, 0,
620 { m_unregistered, m_not_oper, m_ignore, me_gungline, mo_gungline, m_ignore }
621 };
622
623 static void
624 module_init(void)
625 {
626 mod_add_cmd(&gline_msgtab);
627 mod_add_cmd(&ungline_msgtab);
628 add_capability("GLN", CAP_GLN, 1);
629 }
630
631 static void
632 module_exit(void)
633 {
634 mod_del_cmd(&gline_msgtab);
635 mod_del_cmd(&ungline_msgtab);
636 delete_capability("GLN");
637 }
638
639 struct module module_entry = {
640 .node = { NULL, NULL, NULL },
641 .name = NULL,
642 .version = "$Revision$",
643 .handle = NULL,
644 .modinit = module_init,
645 .modexit = module_exit,
646 .flags = 0
647 };

Properties

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