/* Ce programme est l'interface entre les services web et la base de donnees */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "database.h" using namespace std; enum COMMAND { COMMAND_NONE, COMMAND_USER_LOGIN, COMMAND_USER_CREATE, COMMAND_USER_SETINFO, COMMAND_USER_GETINFO, COMMAND_USER_SENDPASS, COMMAND_USER_CHANGE_PASS, COMMAND_USER_ACHAT, COMMAND_COMMENT, COMMAND_COMMENT_RATE, COMMAND_COMMENT_GETRATE, COMMAND_LIST_ACHATS, COMMAND_LIST_USERS, COMMAND_LIST_PIECES, COMMAND_LIST_COMMENTS, COMMAND_PIECE_CREATE, COMMAND_PIECE_SETINFO, COMMAND_PIECE_RATE, COMMAND_PIECE_GETRATE, }; enum EXTRALINE{ EXTRA_NOLINE, EXTRA_MATCH, EXTRA_UPTO, }; struct COMMAND_DEF{ COMMAND cmd; bool sessionkey; // Le premier argument est une cle de session int nbargs; string argdesc; int maxlines; EXTRALINE extra; set keys; COMMAND_DEF(COMMAND _cmd, bool _sessionkey, int _nbargs, const char *_desc, int _maxlines, EXTRALINE _extra){ cmd = _cmd; sessionkey = _sessionkey; nbargs = _nbargs; argdesc = _desc; maxlines = _maxlines; extra = _extra; } COMMAND_DEF(){ cmd = COMMAND_NONE; sessionkey = false; nbargs = 0; maxlines = 0; extra = EXTRA_NOLINE; } void setkey(const string &key){ keys.insert(key); } }; static string empty; struct KEYARG{ string key; string arg; KEYARG(const char *_key, const char *_arg){ key = _key; arg = _arg; } }; struct SESSIONINFO{ time_t last; // Dernière activité string user; int user_id; SESSIONINFO(const char *_user, int _id){ user = _user; user_id = _id; } SESSIONINFO(){ user_id = 0; } void reset(){ user_id = 0; user.clear(); } }; static map sessions; static int fd_urandom = -1; static void keycontrol_initsessionkey () { fd_urandom = open ("/dev/urandom",O_RDONLY,0); if (fd_urandom == -1){ tlmp_error ("Ne peut ouvrir /dev/urandom (%s), termine\n",strerror(errno)); exit (-1); } } static int keycontrol_makesessionkey (char tmp[100]) { int ret = -1; unsigned char buf[8]; if (read(fd_urandom,buf,sizeof(buf))!=sizeof(buf)){ tlmp_error ("Erreur de lecture sur /dev/urandom (%s)\n",strerror(errno)); }else{ struct timeval tv; gettimeofday (&tv,NULL); int len = snprintf (tmp,100,"%ld%ld",tv.tv_sec,tv.tv_usec); sprintf (tmp+len,"%02x%02x%02x%02x%02x%02x%02x%02x" ,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); ret = 0; } return ret; } struct CLIENTINFO: public ARRAY_OBJ{ string ip; string port; SESSIONINFO session; vector args; vector uargs; vector kargs; vector lines; COMMAND_DEF *command; void reset(){ args.clear(); lines.clear(); command = NULL; session.reset(); } CLIENTINFO(){ reset(); } }; static void command_error (CLIENTINFO *cinfo, const char *msg, const char *line) { tlmp_error ("%s: %s: %s\n",msg,cinfo->ip.c_str(),line); } #define _TLMP_command_parse struct _F_command_parse{ #define _F_command_parse_process(x) void x process (CLIENTINFO *cinfo, bool &endclient, bool &logcommand) virtual _F_command_parse_process( )=0; }; static string key_ville = "ville"; static string key_etat = "etat"; static string key_pays = "pays"; static string key_courriel = "courriel"; static string key_nom = "nom"; static string key_prenom = "prenom"; static string key_wallet_out = "wallet_out"; static string key_password = "password"; static string key_oldpassword = "oldpassword"; static string key_newpassword = "newpassword"; static string key_titre = "titre"; static string key_cost = "cost"; static map commands; static void keycontrol_initcmd() { commands["user_login"] = COMMAND_DEF(COMMAND_USER_LOGIN,false,2,"user,password",0,EXTRA_NOLINE); COMMAND_DEF def(COMMAND_USER_CREATE,false,1,"user",0,EXTRA_NOLINE); def.setkey (key_nom); def.setkey (key_prenom); def.setkey (key_password); def.setkey (key_ville); def.setkey (key_etat); def.setkey (key_pays); def.setkey (key_courriel); def.setkey (key_wallet_out); commands["user_create"] = def; def = COMMAND_DEF(COMMAND_USER_SETINFO,true,1,"session",0,EXTRA_NOLINE); def.setkey (key_nom); def.setkey (key_prenom); def.setkey (key_ville); def.setkey (key_etat); def.setkey (key_pays); def.setkey (key_courriel); def.setkey (key_wallet_out); commands["user_setinfo"] = def; commands["user_getinfo"] = COMMAND_DEF(COMMAND_USER_GETINFO,true,1,"session",0,EXTRA_NOLINE); commands["user_sendpass"] = COMMAND_DEF(COMMAND_USER_SENDPASS,false,1,"email",0,EXTRA_NOLINE); def = COMMAND_DEF(COMMAND_USER_CHANGE_PASS,true,1,"session",0,EXTRA_NOLINE); def.setkey (key_oldpassword); def.setkey (key_newpassword); commands["user_change_pass"] = def; commands["user_achat"] = COMMAND_DEF(COMMAND_USER_ACHAT,true,2,"session,piece",0,EXTRA_NOLINE); commands["comment"] = COMMAND_DEF(COMMAND_COMMENT,true,2,"session,pieceid",10,EXTRA_UPTO); commands["list_achats"] = COMMAND_DEF(COMMAND_LIST_ACHATS,true,1,"session",0,EXTRA_NOLINE); commands["list_users"] = COMMAND_DEF(COMMAND_LIST_USERS,false,0,"",0,EXTRA_NOLINE); commands["list_pieces"] = COMMAND_DEF(COMMAND_LIST_PIECES,true,2,"session,piece_id",0,EXTRA_NOLINE); commands["list_comments"] = COMMAND_DEF(COMMAND_LIST_COMMENTS,true,2,"session,pieceid",0,EXTRA_NOLINE); // comment_rate user comment drole interessant commands["comment_rate"] = COMMAND_DEF(COMMAND_COMMENT_RATE,true,4,"session,commentid,drole,interessant",0,EXTRA_NOLINE); commands["comment_getrate"] = COMMAND_DEF(COMMAND_COMMENT_GETRATE,true,2,"session,commentid",0,EXTRA_NOLINE); def = COMMAND_DEF(COMMAND_PIECE_CREATE,true,1,"session",10,EXTRA_UPTO); def.setkey (key_titre); def.setkey (key_cost); commands["piece_create"] = def; def = COMMAND_DEF(COMMAND_PIECE_SETINFO,true,2,"session,pieceid",10,EXTRA_UPTO); def.setkey (key_titre); def.setkey (key_cost); commands["piece_setinfo"] = def; commands["piece_rate"] = COMMAND_DEF(COMMAND_PIECE_RATE,true,5,"session,pieceid,drole,interessant,style",0,EXTRA_NOLINE); commands["piece_getrate"] = COMMAND_DEF(COMMAND_PIECE_GETRATE,true,2,"session,pieceid",0,EXTRA_NOLINE); } static void keycontrol_listcmd() { for (map::iterator it = commands.begin(); it != commands.end(); it++){ COMMAND_DEF &d = it->second; printf ("%20s(%d) session=%d nbargs=%d maxlines=%d extra=%d \"%s\"\n",it->first.c_str() ,d.cmd,d.sessionkey,d.nbargs,d.maxlines,d.extra ,d.argdesc.c_str()); if (d.keys.size() > 0){ printf ("\t\t\t"); for (set::iterator kit = d.keys.begin(); kit != d.keys.end(); kit++){ printf (" %s",kit->c_str()); } printf ("\n"); } } } static void command_parse (_F_command_parse &c, _F_TCPSERVER_V1 *cnet, CLIENTINFO *cinfo, const char *line, bool &endclient) { if (strncmp(line,"dat ",4)==0){ if (cinfo->command == NULL){ command_error (cinfo,"Ligne dat hors contexte",line); endclient = true; }else{ if ((int)cinfo->lines.size() < cinfo->command->maxlines){ cinfo->lines.push_back(line+4); }else{ command_error (cinfo,"Trop de ligne dat",line); endclient = true; } } }else if (strncmp(line,"prm ",4)==0){ if (cinfo->command == NULL){ command_error (cinfo,"Ligne prm hors contexte",line); endclient = true; }else{ SSTRING word; const char *pt = str_copyword (word,line+4); if (pt != NULL){ if (cinfo->command->keys.count(word.c_str())==0){ command_error (cinfo,"Parametre invalide",line); endclient = true; }else{ cinfo->kargs.push_back(KEYARG(word.c_str(),str_skip(pt))); } } } }else if (strcmp(line,"end")==0){ if (cinfo->command == NULL){ command_error (cinfo,"Ligne end hors contexte",line); endclient = true; }else{ if (cinfo->command->extra == EXTRA_MATCH && (int)cinfo->lines.size() != cinfo->command->maxlines){ command_error (cinfo,"Pas assez de ligne",line); }else{ bool logcommand = false; c.process (cinfo,endclient,logcommand); cinfo->reset(); } } }else if (strncmp(line,"cmd ",4)==0){ if (cinfo->command != NULL){ command_error (cinfo,"cmd while in cmd",line); endclient = true; }else{ SSTRINGS tb; int n = str_splitline (line+4,' ',tb); if (n == 0){ command_error (cinfo,"Ligne cmd vide",line); endclient = true; }else{ const char *cmd = tb.getitem(0)->c_str(); map::iterator it = commands.find(cmd); if (it == commands.end()){ command_error (cinfo,"Unknown command",line); endclient = true; }else if (it->second.nbargs != n - 1){ command_error (cinfo,"Invalid argument number",line); endclient = true; }else{ cinfo->command = &it->second; for (int i=1; ic_str(); cinfo->args.push_back(s); cinfo->uargs.push_back(atoi(s)); } if (cinfo->command->sessionkey){ map::iterator it = sessions.find(cinfo->args[0]); if (it == sessions.end()){ command_error (cinfo,"Invalid session key",line); endclient = true; }else{ cinfo->session = it->second; it->second.last = time(NULL); } } if (!endclient && it->second.maxlines == 0 && it->second.keys.size()==0){ bool logcommand = false; c.process (cinfo,endclient,logcommand); cinfo->reset(); } } } } } if (endclient) cnet->send ("err protocol\n"); } static void user_setarg (vector &kargs, C_user &user) { for (unsigned i=0; i &kargs, C_piece &piece) { for (unsigned i=0; i static int user_lookup(const string &user) { glocal int ret = -1; ("select user_id from user where id='%s'",user.c_str()); glocal.ret = atoi(row[0]); return glocal.ret; } #endif static int piece_lookup (int user_id, const string &piece) { return atoi(piece.c_str()); } static SSTRING getnow() { time_t t = time(NULL); struct tm *tt = localtime (&t); char tmp[20]; snprintf (tmp,sizeof(tmp),"%04d/%02d/%02d %02d:%02d:%02d" ,tt->tm_year+1900,tt->tm_mon+1,tt->tm_mday ,tt->tm_hour,tt->tm_min,tt->tm_sec); return SSTRING(tmp); } int main (int argc, char *argv[]) { glocal int ret = -1; glocal const char *port = "8190"; glocal const char *bind = "127.0.0.1"; glocal bool daemon = false; glocal const char *pidfile = "/var/run/keycontrol.pid"; glocal const char *user = "keycontrol"; glocal const char *dbhost = "localhost"; glocal const char *dbname = "thekey"; glocal bool listcmd = false; keycontrol_initcmd(); keycontrol_initsessionkey(); glocal.ret = (argc,argv,"tlmpsql"); setproginfo ("keycontrol",VERSION,""); setgrouparg ("Reseautique"); setarg ('b',"bind","Ecoute sur cette adresse",glocal.bind,false); setarg ('p',"port","Ecoute sur ce port TCP",glocal.port,false); setgrouparg ("Base de donnees"); setarg (' ',"dbhost","Serveur de base de donnees",glocal.dbhost,false); setarg (' ',"dbname","Nom de la base de donnees",glocal.dbname,false); setgrouparg ("Divers"); setarg (' ',"daemon","Execute en arriere plan",glocal.daemon,false); setarg (' ',"pidfile","Fichier PID",glocal.pidfile,false); setarg (' ',"listcmd","Affiche les commandes du protocole",glocal.listcmd,false); int ret = -1; if (glocal.listcmd){ keycontrol_listcmd(); exit(0); } query_setdefaultdb (glocal.dbhost,glocal.dbname); (glocal.bind,glocal.port,5); CLIENTINFO *cinfo = new CLIENTINFO; char ip[20]; ipnum_ip2a (from,ip); cinfo->ip = ip; cinfo->port = info.port; info.data = cinfo; CLIENTINFO *inf = (CLIENTINFO*)info.data; if (inf->command != NULL){ command_error (inf,"Commande incomplete",""); } CLIENTINFO *inf = (CLIENTINFO*)info.data; (this,inf,line,endclient); printf ("commande %d user=%s id=%d",cinfo->command->cmd,cinfo->session.user.c_str(),cinfo->session.user_id); for (unsigned i=0; iargs.size(); i++) printf (" %s",cinfo->args[i].c_str()); printf ("\n"); for (unsigned i=0; ikargs.size(); i++){ printf ("prm %s %s\n" ,cinfo->kargs[i].key.c_str(),cinfo->kargs[i].arg.c_str()); } for (unsigned i=0; ilines.size(); i++) printf ("dat %s\n",cinfo->lines[i].c_str()); switch (cinfo->command->cmd){ case COMMAND_NONE: break; case COMMAND_USER_LOGIN: { ("select user_id,id from user where id='%s' and pass=password('%s')" ,cinfo->args[0].c_str(),cinfo->args[1].c_str()); int id = atoi(row[0]); char tmp[100]; if (keycontrol_makesessionkey(tmp)!=-1){ glocal.TCPSERVER.sendf ("dat ok %s\n",tmp); sessions[tmp] = SESSIONINFO (row[1],id); } glocal.TCPSERVER.send ("err fail\n"); } break; case COMMAND_USER_CREATE: { C_user user; user.pass.setflag (NSQL_IS_PASSWORD); user.id.setfrom (cinfo->args[0].c_str()); user_setarg (cinfo->kargs,user); user.date_create.setfrom (getnow()); user.date_modif.setfrom (user.date_create); user.insert ("user"); logcommand = true; } break; case COMMAND_USER_SENDPASS: { ("select user_id,nom,prenom from user where courriel='%s'",cinfo->args[0].c_str()); glocal.TCPSERVER.send ("dat courriel envoye, mot de passe temporaire\n"); glocal.TCPSERVER.send ("err pas de correspondance\n"); } break; case COMMAND_USER_CHANGE_PASS: { glocal bool *logc = &logcommand; glocal string newpass; string oldpass; for (unsigned i=0; ikargs.size(); i++){ const string &key = cinfo->kargs[i].key; const char *arg = cinfo->kargs[i].arg.c_str(); if (key == key_oldpassword){ oldpass = arg; }else if (key == key_newpassword){ glocal.newpass = arg; } } ("select user_id,id from user where user_id=%d and pass=password('%s')" ,cinfo->session.user_id,oldpass.c_str()); C_user user; user.pass.setflag (NSQL_IS_PASSWORD); user.pass.setfrom (glocal.newpass.c_str()); user.update ("user","user_id=%s",row[0]); *glocal.logc = true; glocal.TCPSERVER.send ("err fail\n"); logcommand = true; } break; case COMMAND_USER_SETINFO: { C_user user; user_setarg (cinfo->kargs,user); user.date_modif.setfrom (getnow()); user.update ("user","user_id=%d",cinfo->session.user_id); logcommand = true; } break; case COMMAND_USER_GETINFO: { ("select * from user where user_id=%d",cinfo->session.user_id); C_user user; user.set (fields,row); glocal.TCPSERVER.sendf ("dat id=%s\n",user.id.c_str()); glocal.TCPSERVER.sendf ("dat nom=%s\n",user.nom.c_str()); glocal.TCPSERVER.sendf ("dat prenom=%s\n",user.prenom.c_str()); glocal.TCPSERVER.sendf ("dat ville=%s\n",user.ville.c_str()); glocal.TCPSERVER.sendf ("dat etat=%s\n",user.etat.c_str()); glocal.TCPSERVER.sendf ("dat pays=%s\n",user.pays.c_str()); glocal.TCPSERVER.sendf ("dat courriel=%s\n",user.courriel.c_str()); glocal.TCPSERVER.sendf ("dat wallet_in=%s\n",user.wallet_in.c_str()); glocal.TCPSERVER.sendf ("dat wallet_out=%s\n",user.wallet_out.c_str()); glocal.TCPSERVER.sendf ("dat date_create=%s\n",user.date_create.c_str()); glocal.TCPSERVER.sendf ("dat date_modif=%s\n",user.date_modif.c_str()); } break; case COMMAND_USER_ACHAT: { } break; case COMMAND_COMMENT: { int user_id = cinfo->session.user_id; int piece_id = piece_lookup(user_id,cinfo->args[1]); if (piece_id == -1){ tlmp_error ("Piece inconnue: %s\n",cinfo->args[1].c_str()); glocal.TCPSERVER.sendf ("err piece inconnue\n"); }else{ C_comment comment; comment.user_id.setfrom (user_id); comment.piece_id.setfrom (piece_id); string tmp; for (unsigned i=0; ilines.size(); i++){ tmp += cinfo->lines[i] + '\n'; } comment.texte.setfrom (tmp.c_str()); comment.date_create.setfrom(getnow()); // fprintf (stderr,"Comment uid=%s pid=%s com=%s\n",comment.user_id.c_str(),comment.piece_id.c_str(),comment.texte.c_str()); comment.insert ("comment"); logcommand = true; } } break; case COMMAND_COMMENT_RATE: { C_comment_rating rate; rate.comment_id.setfrom (cinfo->args[1].c_str()); rate.user_id.setfrom (cinfo->session.user_id); rate.drole.setfrom(cinfo->uargs[2]); rate.interessant.setfrom(cinfo->uargs[3]); rate.insert_or_update ("comment_rating"); logcommand = true; } break; case COMMAND_COMMENT_GETRATE: { ("select * from comment_rating where comment_id=%u",cinfo->uargs[1]); C_comment_rating rate; rate.set (fields,row); glocal.TCPSERVER.sendf ("dat %s %s\n",rate.drole.c_str(),rate.interessant.c_str()); glocal.TCPSERVER.send ("dat ? ?\n"); } break; case COMMAND_LIST_USERS: { ("select id from user"); glocal.TCPSERVER.sendf ("dat %s\n",row[0]); } break; case COMMAND_LIST_ACHATS: { ("select * from achat where user_id=%d",cinfo->session.user_id); C_achat achat; achat.set (fields,row); glocal.TCPSERVER.sendf ("dat piece=%s\n",achat.piece_id.c_str()); glocal.TCPSERVER.sendf ("dat transaction=%s\n",achat.transaction.c_str()); glocal.TCPSERVER.sendf ("dat date=%s\n",achat.date.c_str()); } break; case COMMAND_LIST_PIECES: { ("select * from piece where user_id=%u",cinfo->uargs[1]); C_piece piece; piece.set (fields,row); glocal.TCPSERVER.sendf ("dat piece=%s\n",piece.piece_id.c_str()); glocal.TCPSERVER.sendf ("dat titre=%s\n",piece.titre.c_str()); glocal.TCPSERVER.sendf ("dat date=%s\n",piece.date_create.c_str()); } break; case COMMAND_LIST_COMMENTS: { int user_id = cinfo->session.user_id; if (user_id == -1){ tlmp_error ("Usager inconnue: %s\n",cinfo->args[0].c_str()); glocal.TCPSERVER.sendf ("err utilisateur inconnu\n"); }else{ int piece_id = piece_lookup(user_id,cinfo->args[1]); if (piece_id == -1){ tlmp_error ("Piece inconnue: %s\n",cinfo->args[1].c_str()); glocal.TCPSERVER.sendf ("err piece inconnue\n"); }else{ ("select comment_id, date_create, texte" " from comment where user_id=%d and piece_id=%d",user_id,piece_id); glocal.TCPSERVER.sendf ("dat %s %s\n",row[0],row[1]); } } } break; case COMMAND_PIECE_CREATE: { C_piece piece; piece_setarg (cinfo->kargs,piece); piece.user_id.setfrom (cinfo->session.user_id); string tmp; for (unsigned i=0; ilines.size(); i++){ tmp += cinfo->lines[i] + '\n'; } piece.description.setfrom (tmp.c_str()); piece.date_create.setfrom(getnow()); piece.insert ("piece"); logcommand = true; } break; case COMMAND_PIECE_SETINFO: { C_piece piece; piece_setarg (cinfo->kargs,piece); string tmp; for (unsigned i=0; ilines.size(); i++){ tmp += cinfo->lines[i] + '\n'; } piece.description.setfrom (tmp.c_str()); piece.update ("piece","piece_id=%u and user_id=%d",cinfo->uargs[1],cinfo->session.user_id); logcommand = true; } break; case COMMAND_PIECE_RATE: { C_piece_rating rate; rate.piece_id.setfrom (cinfo->uargs[1]); rate.user_id.setfrom (cinfo->session.user_id); rate.drole.setfrom(cinfo->uargs[2]); rate.interessant.setfrom(cinfo->uargs[3]); rate.style.setfrom(cinfo->uargs[4]); rate.insert_or_update ("piece_rating"); logcommand = true; } break; case COMMAND_PIECE_GETRATE: { ("select * from piece_rating where piece_id=%u",cinfo->uargs[1]); C_piece_rating rate; rate.set (fields,row); glocal.TCPSERVER.sendf ("dat %s %s %s\n",rate.drole.c_str(),rate.interessant.c_str(),rate.style.c_str()); glocal.TCPSERVER.send ("dat ? ? ?\n"); } break; } glocal.TCPSERVER.send ("end\n"); if (o.is_ok()){ if (glocal.daemon){ daemon_init (glocal.pidfile,glocal.user); } o.loop(); ret = 0; } return ret; return glocal.ret; }