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