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