]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/chanserv_relay.c
f3c082bf9c00eb24a38090a17a1ef79a844cca9d
[irc/quakenet/newserv.git] / chanserv / chanserv_relay.c
1 #include "chanserv.h"
2 #include "../control/control.h"
3 #include "../lib/version.h"
4 #include "../lib/irc_string.h"
5 #include "../core/config.h"
6 #include "../lib/hmac.h"
7 #include "../lib/strlfunc.h"
8 #include "../lib/cbc.h"
9 #include "authlib.h"
10
11 #include <stdio.h>
12 #include <string.h>
13
14 #define KEY_BITS 256
15 #define BLOCK_SIZE 16
16
17 MODULE_VERSION(QVERSION);
18
19 int csa_docheckhashpass(void *source, int cargc, char **cargv);
20 int csa_docreateaccount(void *source, int cargc, char **cargv);
21 int csa_dosettempemail(void *source, int cargc, char **cargv);
22 int csa_dosetemail(void *source, int cargc, char **cargv);
23 int csa_doresendemail(void *source, int cargc, char **cargv);
24 int csa_doactivateuser(void *source, int cargc, char **cargv);
25 static int decrypt_password(unsigned char *secret, int keybits, char *buf, int bufsize, char *encrypted);
26 static int hex_to_int(char *input, unsigned char *buf, int buflen);
27
28 static unsigned char createaccountsecret[KEY_BITS / 8];
29 static int createaccountsecret_ok = 0;
30
31 static unsigned char hexlookup[256] = {
32 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
34 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
35 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01,
37 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff,
38 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
39 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
40 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, 0x0c,
42 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
46 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
48 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
56 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
57 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
58 };
59
60 void _init(void) {
61 sstring *s;
62
63 registercontrolhelpcmd("checkhashpass", NO_RELAY, 3, csa_docheckhashpass, "Usage: checkhashpass <username> <digest> ?junk?");
64 registercontrolhelpcmd("settempemail", NO_RELAY, 2, csa_dosettempemail, "Usage: settempemail <userid> <email address>");
65 registercontrolhelpcmd("setemail", NO_RELAY, 3, csa_dosetemail, "Usage: setmail <userid> <timestamp> <email address>");
66 registercontrolhelpcmd("resendemail", NO_RELAY, 1, csa_doresendemail, "Usage: resendemail <userid>");
67 registercontrolhelpcmd("activateuser", NO_RELAY, 1, csa_doactivateuser, "Usage: activateuser <userid>");
68
69 s=getcopyconfigitem("chanserv","createaccountsecret","",128);
70 if(!s || !s->content || !s->content[0]) {
71 Error("chanserv_relay",ERR_WARNING,"createaccountsecret not set, createaccount disabled.");
72 } else if(s->length != KEY_BITS / 8 * 2 || !hex_to_int(s->content, createaccountsecret, sizeof(createaccountsecret))) {
73 Error("chanserv_relay",ERR_WARNING,"createaccountsecret must be a %d character hex string.", KEY_BITS / 8 * 2);
74 } else {
75 registercontrolhelpcmd("createaccount", NO_RELAY, 5, csa_docreateaccount, "Usage: createaccount <execute> <username> <email address> <encrypted password> <activate user>");
76 createaccountsecret_ok = 1;
77 }
78
79 freesstring(s);
80 }
81
82 void _fini(void) {
83 deregistercontrolcmd("checkhashpass", csa_docheckhashpass);
84 deregistercontrolcmd("settempemail", csa_dosettempemail);
85 deregistercontrolcmd("setemail", csa_dosetemail);
86 deregistercontrolcmd("resendemail", csa_doresendemail);
87 deregistercontrolcmd("activateuser", csa_doactivateuser);
88
89 if(createaccountsecret_ok)
90 deregistercontrolcmd("createaccount", csa_docreateaccount);
91 }
92
93 int csa_docheckhashpass(void *source, int cargc, char **cargv) {
94 nick *sender=(nick *)source;
95 reguser *rup;
96 char *flags;
97
98 if(cargc<3) {
99 controlreply(sender, "CHECKHASHPASS FAIL args");
100 return CMD_ERROR;
101 }
102
103 if (!(rup=findreguserbynick(cargv[0]))) {
104 controlreply(sender, "CHECKHASHPASS FAIL user");
105 return CMD_OK;
106 }
107
108 flags = printflags(QUFLAG_ALL & rup->flags, ruflags);
109 if(UHasSuspension(rup)) {
110 controlreply(sender, "CHECKHASHPASS FAIL suspended %s %s %u", rup->username, flags, rup->ID);
111 } else if(UIsInactive(rup)) {
112 controlreply(sender, "CHECKHASHPASS FAIL inactive %s %s %u", rup->username, flags, rup->ID);
113 } else if(!checkhashpass(rup, cargc<3?NULL:cargv[2], cargv[1])) {
114 controlreply(sender, "CHECKHASHPASS FAIL digest %s %s %u", rup->username, flags, rup->ID);
115 } else {
116 controlreply(sender, "CHECKHASHPASS OK %s %s %u %s", rup->username, flags, rup->ID, rup->email?rup->email->content:"-");
117 }
118
119 return CMD_OK;
120 }
121
122 static char *email_to_error(char *email) {
123 maildomain *mdp, *smdp;
124 char *local;
125 char *dupemail;
126 int found = 0;
127 maillock *mlp;
128 reguser *ruh;
129
130 switch(csa_checkeboy_r(email)) {
131 case -1: break;
132 case QM_EMAILTOOSHORT: return "emailshort";
133 case QM_EMAILNOAT: return "emailinvalid";
134 case QM_EMAILATEND: return "emailinvalid";
135 case QM_EMAILINVCHR: return "emailinvalid";
136 case QM_NOTYOUREMAIL: return "emailnotyours";
137 case QM_INVALIDEMAIL: return "emailinvalid";
138 default: return "emailunknown";
139 }
140
141 /* maildomain BS... c&p from hello.c */
142 for(mlp=maillocks;mlp;mlp=mlp->next) {
143 if(!match(mlp->pattern->content, email)) {
144 return "emaillocked";
145 }
146 }
147
148 dupemail = strdup(email);
149 local=strchr(dupemail, '@');
150 if(!local) {
151 free(dupemail);
152 return "emailunknown";
153 }
154 *(local++)='\0';
155
156 mdp=findnearestmaildomain(local);
157 if(mdp) {
158 for(smdp=mdp; smdp; smdp=smdp->parent) {
159 if(MDIsBanned(smdp)) {
160 free(dupemail);
161 return "emaillocked";
162 }
163 if((smdp->count >= smdp->limit) && (smdp->limit > 0)) {
164 free(dupemail);
165 return "emaildomainlimit";
166 }
167 }
168 }
169
170 mdp=findmaildomainbydomain(local);
171 if(mdp) {
172 for (ruh=mdp->users; ruh; ruh=ruh->nextbydomain) {
173 if (ruh->localpart)
174 if (!strcasecmp(dupemail, ruh->localpart->content)) {
175 found++;
176 }
177 }
178
179 if((found >= mdp->actlimit) && (mdp->actlimit > 0)) {
180 free(dupemail);
181 return "emailaddresslimit";
182 }
183 }
184
185 free(dupemail);
186
187 return NULL;
188 }
189
190 static void sendemail(reguser *rup) {
191 csdb_createmail(rup, QMAIL_ACTIVATEEMAIL);
192 }
193
194 int csa_docreateaccount(void *source, int cargc, char **cargv) {
195 nick *sender=(nick *)source;
196 int execute;
197 char *error_username = NULL, *error_password = NULL, *error_email = NULL;
198 char *username = NULL, *password = NULL, *email = NULL;
199 char account_info[512];
200 char passbuf[512];
201 int do_create;
202 int activate;
203
204 if(cargc<5) {
205 controlreply(sender, "CREATEACCOUNT FALSE args");
206 return CMD_ERROR;
207 }
208
209 execute = cargv[0][0] == '1';
210 if(strcmp(cargv[1], "0"))
211 username = cargv[1];
212 if(strcmp(cargv[2], "0"))
213 email = cargv[2];
214 if(strcmp(cargv[3], "0")) {
215 int errorcode = decrypt_password(createaccountsecret, KEY_BITS, passbuf, sizeof(passbuf), cargv[3]);
216 if(errorcode) {
217 Error("chanserv_relay",ERR_WARNING,"createaccount unable to decrypt password, error code: %d", errorcode);
218 controlreply(sender, "CREATEACCOUNT FALSE args");
219 return CMD_ERROR;
220 }
221 password = passbuf;
222 }
223 activate = cargv[4][0] == '1';
224
225 if(username) {
226 if (findreguserbynick(username)) {
227 error_username = "usernameinuse";
228 } else if(csa_checkaccountname_r(username)) {
229 error_username = "usernameinvalid";
230 }
231 }
232
233 if(email)
234 error_email = email_to_error(email);
235
236 if(password) {
237 int r = csa_checkpasswordquality(password);
238 if(r == QM_PWTOSHORT) {
239 error_password = "passwordshort";
240 } else if(r == QM_PWTOLONG) {
241 error_password = "passwordlong";
242 } else if(r == QM_PWTOWEAK) {
243 error_password = "passwordweak";
244 } else if(r != -1) {
245 error_password = "passwordunknown";
246 }
247 }
248
249 if(execute && email && password && username && !error_email && !error_password && !error_username) {
250 reguser *rup;
251 do_create = 1;
252
253 rup = csa_createaccount(username, password, email);
254
255 if(!activate)
256 USetInactive(rup);
257
258 cs_log(sender,"CREATEACCOUNT created auth %s (%s) %s",rup->username,rup->email->content,activate?"(active)": "(inactive)");
259 csdb_createuser(rup);
260 snprintf(account_info, sizeof(account_info), " %u %lu", rup->ID, (unsigned long)rup->lastpasschange);
261
262 sendemail(rup);
263 } else {
264 account_info[0] = '\0';
265 do_create = 0;
266 }
267
268 controlreply(sender, "CREATEACCOUNT %s%s%s%s%s%s%s%s",
269 do_create ? "TRUE" : "FALSE",
270 account_info,
271 email && error_email ? " " : "", email && error_email ? error_email : "",
272 password && error_password ? " " : "", password && error_password ? error_password : "",
273 username && error_username ? " " : "", username && error_username ? error_username : ""
274 );
275
276 return CMD_OK;
277 }
278
279 int csa_dosettempemail(void *source, int cargc, char **cargv) {
280 char *email;
281 char *error;
282 reguser *rup;
283 nick *sender=(nick *)source;
284
285 if(cargc<2) {
286 controlreply(sender, "SETTEMPEMAIL FALSE args");
287 return CMD_ERROR;
288 }
289
290 rup = findreguserbyID(atoi(cargv[0]));
291 if(rup == NULL) {
292 controlreply(sender, "SETTEMPEMAIL FALSE useridnotexist");
293 return CMD_ERROR;
294 }
295
296 if(!UIsInactive(rup)) {
297 controlreply(sender, "SETTEMPEMAIL FALSE accountactive");
298 return CMD_ERROR;
299 }
300
301 email = cargv[1];
302 error = email_to_error(email);
303 if(error) {
304 controlreply(sender, "SETTEMPEMAIL FALSE %s", error);
305 return CMD_ERROR;
306 }
307
308 freesstring(rup->email);
309 rup->email=getsstring(email,EMAILLEN);
310 cs_log(sender,"SETTEMPEMAIL OK username %s email %s",rup->username, rup->email->content);
311
312 csdb_updateuser(rup);
313 sendemail(rup);
314
315 controlreply(sender, "SETTEMPEMAIL TRUE");
316
317 return CMD_OK;
318 }
319
320 int csa_dosetemail(void *source, int cargc, char **cargv) {
321 char *email;
322 char *error;
323 reguser *rup;
324 nick *sender=(nick *)source;
325
326 if(cargc<3) {
327 controlreply(sender, "SETEMAIL FALSE args");
328 return CMD_ERROR;
329 }
330
331 rup = findreguserbyID(atoi(cargv[0]));
332 if(rup == NULL) {
333 controlreply(sender, "SETEMAIL FALSE useridnotexist");
334 return CMD_ERROR;
335 }
336
337 if(UHasStaffPriv(rup)) {
338 controlreply(sender, "SETEMAIL FALSE privuser");
339 return CMD_ERROR;
340 }
341
342 if(UHasSuspension(rup)) {
343 controlreply(sender, "SETEMAIL FALSE suspended");
344 return CMD_ERROR;
345 }
346
347 if(rup->lastpasschange > atoi(cargv[1])) {
348 controlreply(sender, "SETEMAIL FALSE passwordchanged");
349 return CMD_ERROR;
350 }
351
352 email = cargv[2];
353 error = email_to_error(email);
354 if(error) {
355 controlreply(sender, "SETEMAIL FALSE %s", error);
356 return CMD_ERROR;
357 }
358
359 freesstring(rup->email);
360 rup->email=getsstring(email,EMAILLEN);
361 cs_log(sender,"SETEMAIL OK username %s email %s",rup->username, rup->email->content);
362
363 csdb_updateuser(rup);
364 sendemail(rup);
365
366 controlreply(sender, "SETEMAIL TRUE");
367
368 return CMD_OK;
369 }
370
371 int csa_doresendemail(void *source, int cargc, char **cargv) {
372 reguser *rup;
373 nick *sender=(nick *)source;
374
375 if(cargc<1) {
376 controlreply(sender, "RESENDEMAIL FALSE args");
377 return CMD_ERROR;
378 }
379
380 rup = findreguserbyID(atoi(cargv[0]));
381 if(rup == NULL) {
382 controlreply(sender, "RESENDEMAIL FALSE useridnotexist");
383 return CMD_ERROR;
384 }
385
386 if(!UIsInactive(rup)) {
387 controlreply(sender, "RESENDEMAIL FALSE accountactive");
388 return CMD_ERROR;
389 }
390
391 sendemail(rup);
392 controlreply(sender, "RESENDEMAIL TRUE");
393 cs_log(sender,"RESENDEMAIL OK username %s",rup->username);
394
395 return CMD_OK;
396 }
397
398 int csa_doactivateuser(void *source, int cargc, char **cargv) {
399 reguser *rup;
400 nick *sender=(nick *)source;
401
402 if(cargc<1) {
403 controlreply(sender, "ACTIVATEUSER FALSE args");
404 return CMD_ERROR;
405 }
406
407 rup = findreguserbyID(atoi(cargv[0]));
408 if(rup == NULL) {
409 controlreply(sender, "ACTIVATEUSER FALSE useridnotexist");
410 return CMD_ERROR;
411 }
412
413 if(!UIsInactive(rup)) {
414 controlreply(sender, "ACTIVATEUSER FALSE accountactive");
415 return CMD_ERROR;
416 }
417
418 UClearInactive(rup);
419 csdb_updateuser(rup);
420
421 cs_log(sender,"ACTIVATEUSER OK username %s",rup->username);
422 controlreply(sender, "ACTIVATEUSER TRUE");
423
424 return CMD_OK;
425 }
426
427 static int hex_to_int(char *input, unsigned char *buf, int buflen) {
428 int i;
429 for(i=0;i<buflen;i++) {
430 if((0xff == hexlookup[(int)input[i * 2]]) || (0xff == hexlookup[(int)input[i * 2 + 1]])) {
431 return 0;
432 } else {
433 buf[i] = (hexlookup[(int)input[i * 2]] << 4) | hexlookup[(int)input[i * 2 + 1]];
434 }
435 }
436 return 1;
437 }
438
439 static int decrypt_password(unsigned char *secret, int keybits, char *buf, int bufsize, char *encrypted) {
440 size_t ciphertextlen, datalen;
441 unsigned char iv[BLOCK_SIZE];
442 rijndaelcbc *c;
443 int i, j;
444
445 datalen = strlen(encrypted);
446 if(datalen % 2 != 0)
447 return 1;
448 if(datalen < BLOCK_SIZE * 2 * 2)
449 return 2;
450
451 if(!hex_to_int(encrypted, iv, BLOCK_SIZE))
452 return 3;
453
454 ciphertextlen = (datalen - (BLOCK_SIZE * 2)) / 2;
455 if(ciphertextlen > bufsize || ciphertextlen % BLOCK_SIZE != 0)
456 return 4;
457
458 if(!hex_to_int(encrypted + BLOCK_SIZE * 2, (unsigned char *)buf, ciphertextlen))
459 return 5;
460
461 c = rijndaelcbc_init(secret, keybits, iv, 1);
462
463 for(i=0;i<ciphertextlen;i+=BLOCK_SIZE) {
464 char *p = &buf[i];
465 unsigned char *r = rijndaelcbc_decrypt(c, (unsigned char *)p);
466 memcpy(p, r, BLOCK_SIZE);
467
468 for(j=0;j<BLOCK_SIZE;j++) {
469 if(*(p + j) == '\0') {
470 rijndaelcbc_free(c);
471 return 0;
472 }
473 }
474 }
475
476 rijndaelcbc_free(c);
477 return 6;
478 }