ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/modules/nickserv/access.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 10781 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* Nickname access list module.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 #include "services.h"
11 #include "modules.h"
12 #include "conffile.h"
13 #include "language.h"
14 #include "commands.h"
15 #include "databases.h"
16 #include "modules/operserv/operserv.h"
17
18 #include "nickserv.h"
19 #include "ns-local.h"
20
21 /*************************************************************************/
22
23 static Module *module_nickserv;
24
25 static int32 NSAccessMax;
26 static int NSFirstAccessEnable;
27 static int NSFirstAccessWild;
28
29 /*************************************************************************/
30
31 static void do_access(User *u);
32
33 static Command cmds[] = {
34 {"ACCESS", do_access, NULL, NICK_HELP_ACCESS,
35 -1, NICK_OPER_HELP_ACCESS},
36 { NULL }
37 };
38
39 /*************************************************************************/
40 /**************************** Database stuff *****************************/
41 /*************************************************************************/
42
43 /* See autojoin.c for why we don't create our own table. */
44
45 /* Temporary structure for loading/saving access records */
46 typedef struct {
47 uint32 nickgroup;
48 char *mask;
49 } DBRecord;
50 static DBRecord dbrec_static;
51
52 /* Iterators for first/next routines */
53 static NickGroupInfo *db_ngi_iterator;
54 static int db_array_iterator;
55
56 /*************************************************************************/
57
58 /* Table access routines */
59
60 static void *new_access(void)
61 {
62 return memset(&dbrec_static, 0, sizeof(dbrec_static));
63 }
64
65 static void free_access(void *record)
66 {
67 free(((DBRecord *)record)->mask);
68 }
69
70 static void insert_access(void *record)
71 {
72 DBRecord *dbrec = record;
73 NickGroupInfo *ngi = get_nickgroupinfo(dbrec->nickgroup);
74 if (!ngi) {
75 module_log("Discarding access record for missing nickgroup %u: %s",
76 dbrec->nickgroup, dbrec->mask);
77 free_access(record);
78 } else {
79 ARRAY_EXTEND(ngi->access);
80 ngi->access[ngi->access_count-1] = dbrec->mask;
81 }
82 }
83
84 static void *next_access(void)
85 {
86 while (db_ngi_iterator
87 && db_array_iterator >= db_ngi_iterator->access_count
88 ) {
89 db_ngi_iterator = next_nickgroupinfo();
90 db_array_iterator = 0;
91 }
92 if (db_ngi_iterator) {
93 dbrec_static.nickgroup = db_ngi_iterator->id;
94 dbrec_static.mask = db_ngi_iterator->access[db_array_iterator++];
95 return &dbrec_static;
96 } else {
97 return NULL;
98 }
99 }
100
101 static void *first_access(void)
102 {
103 db_ngi_iterator = first_nickgroupinfo();
104 db_array_iterator = 0;
105 return next_access();
106 }
107
108 /*************************************************************************/
109
110 /* Database table definition */
111
112 #define FIELD(name,type,...) \
113 { #name, type, offsetof(DBRecord,name) , ##__VA_ARGS__ }
114
115 static DBField access_dbfields[] = {
116 FIELD(nickgroup, DBTYPE_UINT32),
117 FIELD(mask, DBTYPE_STRING),
118 { NULL }
119 };
120
121 static DBTable access_dbtable = {
122 .name = "nick-access",
123 .newrec = new_access,
124 .freerec = free_access,
125 .insert = insert_access,
126 .first = first_access,
127 .next = next_access,
128 .fields = access_dbfields,
129 };
130
131 #undef FIELD
132
133 /*************************************************************************/
134 /**************************** Local routines *****************************/
135 /*************************************************************************/
136
137 /* Handle the ACCESS command. */
138
139 static void do_access(User *u)
140 {
141 char *cmd = strtok(NULL, " ");
142 char *mask = strtok(NULL, " ");
143 NickInfo *ni;
144 NickGroupInfo *ngi;
145 int i;
146
147 if (cmd && stricmp(cmd, "LIST") == 0 && mask && is_services_admin(u)) {
148 ni = get_nickinfo(mask);
149 ngi = NULL;
150 if (!ni) {
151 notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, mask);
152 } else if (ni->status & NS_VERBOTEN) {
153 notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, mask);
154 } else if (!(ngi = get_ngi(ni))) {
155 notice_lang(s_NickServ, u, INTERNAL_ERROR);
156 } else if (ngi->access_count == 0) {
157 notice_lang(s_NickServ, u, NICK_ACCESS_LIST_X_EMPTY, mask);
158 } else {
159 notice_lang(s_NickServ, u, NICK_ACCESS_LIST_X, mask);
160 ARRAY_FOREACH (i, ngi->access)
161 notice(s_NickServ, u->nick, " %s", ngi->access[i]);
162 }
163 put_nickinfo(ni);
164 put_nickgroupinfo(ngi);
165
166 } else if (!cmd || ((stricmp(cmd,"LIST")==0) ? mask!=NULL : mask==NULL)) {
167 syntax_error(s_NickServ, u, "ACCESS", NICK_ACCESS_SYNTAX);
168
169 } else if (mask && !strchr(mask, '@')) {
170 notice_lang(s_NickServ, u, BAD_USERHOST_MASK);
171 notice_lang(s_NickServ, u, MORE_INFO, s_NickServ, "ACCESS");
172
173 } else if (ngi = u->ngi, !(ni = u->ni)) {
174 notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);
175
176 } else if (!user_identified(u)) {
177 notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
178
179 } else if (stricmp(cmd, "ADD") == 0) {
180 if (readonly) {
181 notice_lang(s_NickServ, u, NICK_ACCESS_DISABLED);
182 return;
183 }
184 if (ngi->access_count >= NSAccessMax) {
185 notice_lang(s_NickServ, u, NICK_ACCESS_REACHED_LIMIT, NSAccessMax);
186 return;
187 }
188 ARRAY_FOREACH (i, ngi->access) {
189 if (stricmp(ngi->access[i], mask) == 0) {
190 notice_lang(s_NickServ, u, NICK_ACCESS_ALREADY_PRESENT, mask);
191 return;
192 }
193 }
194 if (strchr(mask, '!'))
195 notice_lang(s_NickServ, u, NICK_ACCESS_NO_NICKS);
196 ARRAY_EXTEND(ngi->access);
197 ngi->access[ngi->access_count-1] = sstrdup(mask);
198 notice_lang(s_NickServ, u, NICK_ACCESS_ADDED, mask);
199
200 } else if (stricmp(cmd, "DEL") == 0) {
201 if (readonly) {
202 notice_lang(s_NickServ, u, NICK_ACCESS_DISABLED);
203 return;
204 }
205 /* First try for an exact match; then, a case-insensitive one. */
206 ARRAY_SEARCH_PLAIN(ngi->access, mask, strcmp, i);
207 if (i == ngi->access_count)
208 ARRAY_SEARCH_PLAIN(ngi->access, mask, stricmp, i);
209 if (i == ngi->access_count) {
210 notice_lang(s_NickServ, u, NICK_ACCESS_NOT_FOUND, mask);
211 return;
212 }
213 notice_lang(s_NickServ, u, NICK_ACCESS_DELETED, ngi->access[i]);
214 free(ngi->access[i]);
215 ARRAY_REMOVE(ngi->access, i);
216
217 } else if (stricmp(cmd, "LIST") == 0) {
218 if (ngi->access_count == 0) {
219 notice_lang(s_NickServ, u, NICK_ACCESS_LIST_EMPTY);
220 } else {
221 notice_lang(s_NickServ, u, NICK_ACCESS_LIST);
222 ARRAY_FOREACH (i, ngi->access)
223 notice(s_NickServ, u->nick, " %s", ngi->access[i]);
224 }
225
226 } else {
227 syntax_error(s_NickServ, u, "ACCESS", NICK_ACCESS_SYNTAX);
228
229 }
230 }
231
232 /*************************************************************************/
233 /*************************** Callback routines ***************************/
234 /*************************************************************************/
235
236 /* Nick-registration callback (initializes access list). */
237
238 static int do_registered(User *u, NickInfo *ni, NickGroupInfo *ngi,
239 int *replied)
240 {
241 if (NSFirstAccessEnable) {
242 ngi->access_count = 1;
243 ngi->access = smalloc(sizeof(char *));
244 if (NSFirstAccessWild) {
245 ngi->access[0] = create_mask(u, 0);
246 } else {
247 ngi->access[0] = smalloc(strlen(u->username)+strlen(u->host)+2);
248 sprintf(ngi->access[0], "%s@%s", u->username, u->host);
249 }
250 }
251 return 0;
252 }
253
254 /*************************************************************************/
255
256 /* Check whether a user is on the access list of the nick they're using.
257 * Return 1 if on the access list, 0 if not.
258 */
259
260 static int check_on_access(User *u)
261 {
262 int i;
263 char buf[BUFSIZE];
264
265 if (!u->ni || !u->ngi) {
266 module_log("check_on_access() BUG: ni or ngi is NULL!");
267 return 0;
268 }
269 if (u->ngi->access_count == 0)
270 return 0;
271 i = strlen(u->username);
272 snprintf(buf, sizeof(buf), "%s@%s", u->username, u->host);
273 ARRAY_FOREACH (i, u->ngi->access) {
274 if (match_wild_nocase(u->ngi->access[i], buf))
275 return 1;
276 }
277 return 0;
278 }
279
280 /*************************************************************************/
281 /***************************** Module stuff ******************************/
282 /*************************************************************************/
283
284 ConfigDirective module_config[] = {
285 { "NSAccessMax", { { CD_POSINT, CF_DIRREQ, &NSAccessMax } } },
286 { "NSFirstAccessEnable",{{CD_SET, 0, &NSFirstAccessEnable } } },
287 { "NSFirstAccessWild",{ { CD_SET, 0, &NSFirstAccessWild } } },
288 { NULL }
289 };
290
291 /*************************************************************************/
292
293 int init_module()
294 {
295 if (NSAccessMax > MAX_NICK_ACCESS) {
296 module_log("NSAccessMax upper-bounded at MAX_NICK_ACCESS (%d)",
297 MAX_NICK_ACCESS);
298 NSAccessMax = MAX_NICK_ACCESS;
299 }
300
301 module_nickserv = find_module("nickserv/main");
302 if (!module_nickserv) {
303 module_log("Main NickServ module not loaded");
304 return 0;
305 }
306 use_module(module_nickserv);
307
308 if (!register_commands(module_nickserv, cmds)) {
309 module_log("Unable to register commands");
310 exit_module(0);
311 return 0;
312 }
313
314 if (!add_callback(module_nickserv, "check recognized", check_on_access)
315 || !add_callback(module_nickserv, "registered", do_registered)
316 ) {
317 module_log("Unable to add callbacks");
318 exit_module(0);
319 return 0;
320 }
321
322 if (!register_dbtable(&access_dbtable)) {
323 module_log("Unable to register database table");
324 exit_module(0);
325 return 0;
326 }
327
328 return 1;
329 }
330
331 /*************************************************************************/
332
333 int exit_module(int shutdown_unused)
334 {
335 unregister_dbtable(&access_dbtable);
336
337 if (module_nickserv) {
338 remove_callback(module_nickserv, "registered", do_registered);
339 remove_callback(module_nickserv, "check recognized", check_on_access);
340 unregister_commands(module_nickserv, cmds);
341 unuse_module(module_nickserv);
342 module_nickserv = NULL;
343 }
344
345 return 1;
346 }
347
348 /*************************************************************************/
349
350 /*
351 * Local variables:
352 * c-file-style: "stroustrup"
353 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
354 * indent-tabs-mode: nil
355 * End:
356 *
357 * vim: expandtab shiftwidth=4:
358 */