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