]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * NOperserv v0.01 | |
3 | * | |
4 | * A replacement for Germania's ageing Operservice2 | |
5 | * | |
6 | * Copyright (C) 2005 Chris Porter. | |
7 | */ | |
8 | ||
9 | #include "../localuser/localuser.h" | |
10 | #include "../lib/irc_string.h" | |
11 | #include "../lib/strlfunc.h" | |
12 | #include "../lib/version.h" | |
13 | #include "../authext/authext.h" | |
14 | #include "../control/control.h" | |
15 | #include "../control/control_db.h" | |
16 | #include "../control/control_policy.h" | |
17 | ||
18 | #include <stdio.h> | |
19 | #include <string.h> | |
20 | #include <stdarg.h> | |
21 | ||
22 | MODULE_VERSION(""); | |
23 | ||
24 | #define FLAGBUFLEN 100 | |
25 | ||
26 | #define NO_FOUND_NICKNAME 1 | |
27 | #define NO_FOUND_AUTHNAME 2 | |
28 | ||
29 | /* @test */ | |
30 | static int noperserv_hello(void *sender, int cargc, char **cargv) { | |
31 | authname *newaccount = NULL; | |
32 | no_autheduser *au; | |
33 | nick *np = (nick *)sender, *np2, *target = NULL; | |
34 | ||
35 | if(cargc == 0) { | |
36 | newaccount = np->auth; | |
37 | } else { | |
38 | if(cargv[0][0] == '#') { | |
39 | authname *a = getauthbyname(cargv[0] + 1); | |
40 | if(!a) { | |
41 | controlreply(np, "Cannot find anyone with that authname on the network."); | |
42 | return CMD_ERROR; | |
43 | } | |
44 | newaccount = a; | |
45 | } else { | |
46 | target = getnickbynick(cargv[0]); | |
47 | if(!target) { | |
48 | controlreply(np, "Supplied nickname is not on the network."); | |
49 | return CMD_ERROR; | |
50 | } | |
51 | newaccount = target->auth; | |
52 | } | |
53 | } | |
54 | if(!newaccount) { | |
55 | controlreply(np, "Supplied user is not authed with the network."); | |
56 | return CMD_ERROR; | |
57 | } | |
58 | au = noperserv_get_autheduser(newaccount); | |
59 | if(au) { | |
60 | controlreply(np, "Authname already registered."); | |
61 | return CMD_ERROR; | |
62 | } | |
63 | ||
64 | au = noperserv_new_autheduser(newaccount->userid, newaccount->name); | |
65 | if(!au) { | |
66 | controlreply(np, "Memory allocation error."); | |
67 | return CMD_ERROR; | |
68 | } | |
69 | ||
70 | if(noperserv_get_autheduser_count() == 1) { | |
71 | au->authlevel = NO_FIRST_USER_LEVEL; | |
72 | au->noticelevel = NO_FIRST_USER_DEFAULT_NOTICELEVEL; | |
73 | } else { | |
74 | au->authlevel = NO_DEFAULT_LEVEL; | |
75 | au->noticelevel = NO_DEFAULT_NOTICELEVEL; | |
76 | } | |
77 | ||
78 | noperserv_update_autheduser(au); | |
79 | ||
80 | for(np2=newaccount->nicks;np2;np2=np2->nextbyauthname) { | |
81 | controlreply(np2, "An account has been created for you (auth %s).", au->authname->name); | |
82 | if(NOGetAuthLevel(au)) | |
83 | controlreply(np2, "User flags: %s", printflags(NOGetAuthLevel(au), no_userflags)); | |
84 | controlreply(np2, "Notice flags: %s", printflags(NOGetNoticeLevel(au), no_noticeflags)); | |
85 | } | |
86 | ||
87 | if(np->auth==newaccount) { /* send a message to the person who HELLO'ed if we haven't already been told */ | |
88 | controlreply(np, "Account created for auth %s.", au->authname->name); | |
89 | if(NOGetAuthLevel(au)) | |
90 | controlreply(np, "User flags: %s", printflags(NOGetAuthLevel(au), no_userflags)); | |
91 | controlreply(np, "Notice flags: %s", printflags(NOGetNoticeLevel(au), no_noticeflags)); | |
92 | controlreply(np, "Instructions sent to all authed users."); | |
93 | } else if(newaccount->nicks && newaccount->nicks->next) { /* if we have already been told, tell the user it was sent to more than themselves */ | |
94 | controlreply(np, "Instructions sent to all authed users."); | |
95 | } | |
96 | ||
97 | controlwall(NO_OPERED, NL_MANAGEMENT, "%s/%s just HELLO'ed: %s", np->nick, np->authname, au->authname->name); | |
98 | return CMD_OK; | |
99 | } | |
100 | ||
101 | static no_autheduser *noperserv_autheduser_from_command(nick *np, char *command, int *typefound, char **returned) { | |
102 | no_autheduser *au; | |
103 | authname *anp; | |
104 | if(command[0] == '#') { | |
105 | anp = findauthnamebyname(command + 1); | |
106 | if(!anp) { | |
107 | controlreply(np, "Authname not found."); | |
108 | return NULL; | |
109 | } | |
110 | au = noperserv_get_autheduser(anp); | |
111 | if(!au) { | |
112 | controlreply(np, "Authname not found."); | |
113 | } else { | |
114 | *typefound = NO_FOUND_AUTHNAME; | |
115 | *returned = au->authname->name; | |
116 | return au; | |
117 | } | |
118 | } else { | |
119 | nick *np2 = getnickbynick(command); | |
120 | if(!np2) { | |
121 | controlreply(np, "Nickname not on the network."); | |
122 | return NULL; | |
123 | } | |
124 | if(!IsAccount(np2)) { | |
125 | controlreply(np, "User is not authed with the network."); | |
126 | return NULL; | |
127 | } | |
128 | au = NOGetAuthedUser(np2); | |
129 | if(!au) { | |
130 | controlreply(np, "User does not have an account."); | |
131 | } else { | |
132 | *typefound = NO_FOUND_NICKNAME; | |
133 | *returned = np2->nick; | |
134 | return au; | |
135 | } | |
136 | } | |
137 | ||
138 | return NULL; | |
139 | } | |
140 | ||
141 | static int noperserv_noticeflags(void *sender, int cargc, char **cargv) { | |
142 | nick *np2, *np = (nick *)sender; | |
143 | no_autheduser *au; | |
144 | ||
145 | if(cargc == 1) { | |
146 | if((cargv[0][0] == '+') || (cargv[0][0] == '-')) { | |
147 | int ret; | |
148 | au = NOGetAuthedUser(np); | |
149 | flag_t fwas = NOGetNoticeLevel(au), permittedchanges = noperserv_policy_permitted_noticeflags(au); | |
150 | ||
151 | ret = setflags(&au->noticelevel, permittedchanges, cargv[0], no_noticeflags, REJECT_DISALLOWED | REJECT_UNKNOWN); | |
152 | if(ret != REJECT_UNKNOWN) { | |
153 | if(ret == REJECT_DISALLOWED) { | |
154 | flag_t fnow = fwas; | |
155 | setflags(&fnow, NL_ALL, cargv[0], no_noticeflags, REJECT_NONE); | |
156 | if(fnow == fwas) { | |
157 | controlreply(np, "No changes made to existing flags."); | |
158 | } else { | |
159 | char ourflags[FLAGBUFLEN], ournoticeflags[FLAGBUFLEN]; | |
160 | controlreply(np, "Flag alterations denied."); | |
161 | ||
162 | strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags)); | |
163 | strlcpy(ournoticeflags, printflags(NOGetNoticeLevel(au), no_noticeflags), sizeof(ournoticeflags)); | |
164 | controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to NOTICEFLAGS (%s): %s", np->nick, np->authname, ourflags, ournoticeflags, printflagdiff(fwas, fnow, no_noticeflags)); | |
165 | return CMD_ERROR; | |
166 | } | |
167 | } else if(ret == REJECT_NONE) { | |
168 | if(NOGetNoticeLevel(au) == fwas) { | |
169 | controlreply(np, "No changes made to existing flags."); | |
170 | } else { | |
171 | char ourflags[FLAGBUFLEN], ournoticeflags[FLAGBUFLEN], diff[FLAGBUFLEN * 2 + 1], finalflags[FLAGBUFLEN]; | |
172 | noperserv_update_autheduser(au); | |
173 | controlreply(np, "Flag alterations complete."); | |
174 | ||
175 | strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags)); | |
176 | strlcpy(ournoticeflags, printflags(fwas, no_noticeflags), sizeof(ournoticeflags)); | |
177 | strlcpy(diff, printflagdiff(fwas, NOGetNoticeLevel(au), no_noticeflags), sizeof(diff)); | |
178 | controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used NOTICEFLAGS (%s): %s", np->nick, np->authname, ourflags, ournoticeflags, diff); | |
179 | ||
180 | strlcpy(finalflags, printflags(NOGetNoticeLevel(au), no_noticeflags), sizeof(finalflags)); | |
181 | for(np2=au->authname->nicks;np2;np2=np2->nextbyauthname) | |
182 | if(np2 != np) { | |
183 | controlreply(np2, "!!! %s just used NOTICEFLAGS (%s): %s", np->nick, ournoticeflags, diff); | |
184 | controlreply(np2, "Your notice flags are %s", finalflags); | |
185 | } | |
186 | } | |
187 | } | |
188 | } else { | |
189 | controlreply(np, "Unknown flag(s) supplied."); | |
190 | return CMD_ERROR; | |
191 | } | |
192 | } else { | |
193 | int typefound; | |
194 | char *itemfound; | |
195 | au = noperserv_autheduser_from_command(np, cargv[0], &typefound, &itemfound); | |
196 | if(!au) | |
197 | return CMD_ERROR; | |
198 | ||
199 | if(au != NOGetAuthedUser(np)) { | |
200 | controlreply(np, "Notice flags for %s %s are: %s", typefound==NO_FOUND_NICKNAME?"user":"authname", itemfound, printflags(NOGetNoticeLevel(au), no_noticeflags)); | |
201 | return CMD_OK; | |
202 | } | |
203 | } | |
204 | } else { | |
205 | au = NOGetAuthedUser(np); | |
206 | } | |
207 | ||
208 | if(!au) /* shouldn't happen */ | |
209 | return CMD_ERROR; | |
210 | ||
211 | controlreply(np, "Your notice flags are: %s", printflags(NOGetNoticeLevel(au), no_noticeflags)); | |
212 | ||
213 | return CMD_OK; | |
214 | } | |
215 | ||
216 | /* @test */ | |
217 | static int noperserv_deluser(void *sender, int cargc, char **cargv) { | |
218 | nick *np2, *np = (nick *)sender; | |
219 | no_autheduser *target /* target user */, *au = NOGetAuthedUser(np); /* user executing command */ | |
220 | char *userreturned = NULL; /* nickname or authname of the target, pulled from the db */ | |
221 | int typefound; /* whether it was an authname or a username */ | |
222 | char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN], deleteduser[NOMax(ACCOUNTLEN, NICKLEN) + 1]; | |
223 | ||
224 | if(cargc != 1) | |
225 | return CMD_USAGE; | |
226 | ||
227 | target = noperserv_autheduser_from_command(np, cargv[0], &typefound, &userreturned); | |
228 | if(!target) | |
229 | return CMD_ERROR; | |
230 | ||
231 | strlcpy(targetflags, printflags(NOGetAuthLevel(target), no_userflags), sizeof(targetflags)); | |
232 | strlcpy(ourflags, printflags(NOGetAuthLevel(au), no_userflags), sizeof(ourflags)); | |
233 | ||
234 | /* we have to copy it as it might point to an autheduser, which we're about to delete */ | |
235 | strlcpy(deleteduser, userreturned, sizeof(deleteduser)); | |
236 | ||
237 | /* we have to check if target != au, because if successful policy_modification_permitted just returns the flags we're allowed | |
238 | to modify, if we have no flags we won't be able to delete ourselves */ | |
239 | if((target != au) && !noperserv_policy_permitted_modifications(au, target)) { | |
240 | controlreply(np, "Deletion denied."); | |
241 | controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to DELUSER %s (%s)", np->nick, np->authname, ourflags, target->authname->name, targetflags); | |
242 | ||
243 | return CMD_ERROR; | |
244 | } | |
245 | ||
246 | for(np2=target->authname->nicks;np2;np2=np2->nextbyauthname) | |
247 | if(np2 != np) | |
248 | controlreply(np2, "!!! %s/%s (%s) just DELUSERed you.", np->nick, np->authname, ourflags); | |
249 | ||
250 | noperserv_delete_autheduser(target); | |
251 | ||
252 | controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used DELUSER on %s (%s)", np->nick, np->authname, ourflags, deleteduser, targetflags); | |
253 | ||
254 | if(target == au) { | |
255 | controlreply(np, "You have been deleted."); | |
256 | } else { | |
257 | controlreply(np, "%s %s deleted.", typefound==NO_FOUND_AUTHNAME?"Auth":"User", deleteduser); | |
258 | } | |
259 | ||
260 | return CMD_OK; | |
261 | } | |
262 | ||
263 | /* @test */ | |
264 | /* this command needs LOTS of checking */ | |
265 | static int noperserv_userflags(void *sender, int cargc, char **cargv) { | |
266 | nick *np2, *np = (nick *)sender; | |
267 | no_autheduser *au = NOGetAuthedUser(np), *target = NULL; | |
268 | char *flags = NULL, *nicktarget = NULL; | |
269 | int typefound; | |
270 | ||
271 | if(cargc == 0) { | |
272 | target = au; | |
273 | } else if(cargc == 1) { | |
274 | if((cargv[0][0] == '+') || (cargv[0][0] == '-')) { /* modify our own */ | |
275 | flags = cargv[0]; | |
276 | target = au; | |
277 | } else { /* viewing someone elses */ | |
278 | nicktarget = cargv[0]; | |
279 | } | |
280 | } else if(cargc == 2) { | |
281 | nicktarget = cargv[0]; | |
282 | flags = cargv[1]; | |
283 | } else { | |
284 | return CMD_USAGE; | |
285 | } | |
286 | ||
287 | if(nicktarget) { | |
288 | target = noperserv_autheduser_from_command(np, nicktarget, &typefound, &nicktarget); | |
289 | if(!target) | |
290 | return CMD_ERROR; | |
291 | } | |
292 | ||
293 | if(flags) { | |
294 | int ret; | |
295 | flag_t permitted = noperserv_policy_permitted_modifications(au, target), fwas = NOGetAuthLevel(target), fours = NOGetAuthLevel(au); | |
296 | ||
297 | ret = setflags(&target->authlevel, permitted, flags, no_userflags, REJECT_DISALLOWED | REJECT_UNKNOWN); | |
298 | if(ret != REJECT_UNKNOWN) { | |
299 | if(ret == REJECT_DISALLOWED) { | |
300 | flag_t fnow = fwas; | |
301 | setflags(&fnow, NO_ALL_FLAGS, flags, no_userflags, REJECT_NONE); | |
302 | if(fnow == fwas) { | |
303 | controlreply(np, "No changes made to existing flags."); | |
304 | } else { | |
305 | char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN]; | |
306 | controlreply(np, "Flag alterations denied."); | |
307 | ||
308 | strlcpy(targetflags, printflags(fwas, no_userflags), sizeof(targetflags)); | |
309 | strlcpy(ourflags, printflags(fours, no_userflags), sizeof(ourflags)); | |
310 | ||
311 | controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) attempted to use USERFLAGS on %s (%s): %s", np->nick, np->authname, ourflags, target->authname->name, targetflags, printflagdiff(fwas, fnow, no_userflags)); | |
312 | return CMD_ERROR; | |
313 | } | |
314 | } else if(ret == REJECT_NONE) { | |
315 | if(NOGetAuthLevel(target) == fwas) { | |
316 | controlreply(np, "No changes made to existing flags."); | |
317 | } else { | |
318 | char targetflags[FLAGBUFLEN], ourflags[FLAGBUFLEN], finalflags[FLAGBUFLEN]; | |
319 | ||
320 | noperserv_policy_update_noticeflags(fwas, target); | |
321 | noperserv_update_autheduser(target); | |
322 | ||
323 | controlreply(np, "Flag alterations complete."); | |
324 | ||
325 | strlcpy(targetflags, printflags(fwas, no_userflags), sizeof(targetflags)); | |
326 | strlcpy(ourflags, printflags(fours, no_userflags), sizeof(ourflags)); | |
327 | ||
328 | controlwall(NO_OPER, NL_MANAGEMENT, "%s/%s (%s) successfully used USERFLAGS on %s (%s): %s", np->nick, np->authname, ourflags, target->authname->name, targetflags, printflagdiff(fwas, NOGetAuthLevel(target), no_userflags)); | |
329 | ||
330 | strlcpy(finalflags, printflags(NOGetAuthLevel(target), no_userflags), sizeof(finalflags)); | |
331 | for(np2=target->authname->nicks;np2;np2=np2->nextbyauthname) | |
332 | if(np2 != np) { | |
333 | controlreply(np2, "!!! %s/%s (%s) just used USERFLAGS on you (%s): %s", np->nick, np->authname, ourflags, targetflags, printflagdiff(fwas, NOGetAuthLevel(target), no_userflags)); | |
334 | controlreply(np2, "Your user flags are now: %s", finalflags); | |
335 | controlreply(np2, "Your notice flags are now: %s", printflags(target->noticelevel, no_noticeflags)); | |
336 | } | |
337 | } | |
338 | } | |
339 | } else { | |
340 | controlreply(np, "Unknown flag(s) supplied."); | |
341 | return CMD_ERROR; | |
342 | } | |
343 | } | |
344 | ||
345 | if(target != au) { | |
346 | controlreply(np, "User flags for %s %s: %s", typefound==NO_FOUND_AUTHNAME?"auth":"user", nicktarget, printflags(NOGetAuthLevel(target), no_userflags)); | |
347 | controlreply(np, "Notice flags for %s %s: %s", typefound==NO_FOUND_AUTHNAME?"auth":"user", nicktarget, printflags(target->noticelevel, no_noticeflags)); | |
348 | } else { | |
349 | controlreply(np, "Your user flags are: %s", printflags(NOGetAuthLevel(target), no_userflags)); | |
350 | controlreply(np, "Your notice flags are: %s", printflags(target->noticelevel, no_noticeflags)); | |
351 | } | |
352 | ||
353 | return CMD_OK; | |
354 | } | |
355 | ||
356 | void _init() { | |
357 | registercontrolhelpcmd("hello", NO_OPERED | NO_AUTHED, 1, &noperserv_hello, "Syntax: HELLO ?nickname|#authname?\nCreates an account on the service for the specified nick, or if one isn't supplied, your nickname."); | |
358 | registercontrolhelpcmd("userflags", NO_ACCOUNT, 2, &noperserv_userflags, | |
359 | "Syntax: USERFLAGS <nickname|#authname> ?modifications?\n" | |
360 | " Views and modifies user permissions.\n" | |
361 | " If no nickname or authname is supplied, you are substituted for it.\n" | |
362 | " If no flags are supplied, flags are just displayed instead of modified." | |
363 | " Flags:\n" | |
364 | " +o: Operator\n" | |
365 | " +s: Staff member\n" | |
366 | " +S: Security team member\n" | |
367 | " +d: NOperserv developer\n" | |
368 | " +t: Trust queue worker\n" | |
369 | " +Y: Relay\n" | |
370 | " Additional flags may show up in SHOWCOMMANDS but are not userflags as such:\n" | |
371 | " +r: Authed user\n" | |
372 | " +R: Registered NOperserv user\n" | |
373 | " +O: Must be /OPER'ed\n" | |
374 | " +L: Legacy command\n" | |
375 | ); | |
376 | registercontrolhelpcmd("noticeflags", NO_ACCOUNT, 1, &noperserv_noticeflags, | |
377 | "Syntax: NOTICEFLAGS ?(nickname|#authname)|flags?\n" | |
378 | " This command can view and modify your own notice flags, and view that of other users.\n" | |
379 | " Flags:\n" | |
380 | " +m: Management (hello, password, userflags, noticeflags)\n" | |
381 | " +t: Trusts\n" | |
382 | " +k: KICK/KILL commands\n" | |
383 | " +g: GLINE commands\n" | |
384 | " +G: automated gline messages\n" | |
385 | " +h: Shows when glines are set by code (hits)\n" | |
386 | " +c: Clone information\n" | |
387 | " +C: CLEARCHAN command\n" | |
388 | " +f: FAKEUSER commands\n" | |
389 | " +b: BROADCAST commands\n" | |
390 | " +o: Operation commands, such as insmod, rmmod, die, etc\n" | |
391 | " +O: /OPER\n" | |
392 | " +I: Misc commands (resync, etc)\n" | |
393 | " +a: Automated cleanup notices\n" | |
394 | " +n: Sends notices instead of privmsgs\n" | |
395 | " +A: Every single command sent to the service (spammy)\n" | |
396 | ); | |
397 | ||
398 | registercontrolhelpcmd("deluser", NO_OPERED | NO_ACCOUNT, 2, &noperserv_deluser, "Syntax: DELUSER <nickname|#authname>\nDeletes the specified user."); | |
399 | } | |
400 | ||
401 | void _fini() { | |
402 | deregistercontrolcmd("noticeflags", &noperserv_noticeflags); | |
403 | deregistercontrolcmd("userflags", &noperserv_userflags); | |
404 | deregistercontrolcmd("noticeflags", &noperserv_noticeflags); | |
405 | deregistercontrolcmd("hello", &noperserv_hello); | |
406 | deregistercontrolcmd("deluser", &noperserv_deluser); | |
407 | } | |
408 |