#ifndef TRLITOOL_H #define TRLITOOL_H #define PROTOCOL_VERSION "V1" #include #include #include #include #include #include class TCPSERVER_V1; #define REQ_BUF_SIZE 65536 #define REQ_CONTENT_CHUNK 40000 // Some place for base64 // Binary object class BOB_TYPE{ void *buffer; size_t size; // Amount of bytes in the buffer bool owner; // Do we own this buffer void reset(){ buffer = NULL; size = 0; owner = false; } public: BOB_TYPE(){ reset(); } BOB_TYPE (size_t _size); BOB_TYPE (const void *_buffer, size_t _size, bool copy){ reset(); setbuffer (_buffer,_size,copy); } BOB_TYPE (const BOB_TYPE &b){ reset(); setbuffer(b.buffer,b.size,true); } BOB_TYPE &operator = (const BOB_TYPE &b){ reset(); setbuffer (b.buffer,b.size,true); return *this; } ~BOB_TYPE(){ if (owner) free (buffer); } void clear(){ if (owner) free (buffer); reset(); } void setbuffer (const void *_buffer, size_t _size, bool copy); size_t getsize() const { return size; } void *getbuffer() const { return buffer; } }; void _assign (std::vector> &d, const std::vector> &s); void _assign (std::vector &d, const std::vector &s); class EXTRABYTES{ char buf[REQ_BUF_SIZE]; int nb=0; public: int get (char line[REQ_BUF_SIZE+1]){ int ret = 0; if (nb > 0 && nb <= REQ_BUF_SIZE){ ret = nb; memcpy (line,buf,nb); nb = 0; } return ret; } void save (const char *line, int size){ if (size <= REQ_BUF_SIZE){ memcpy (buf,line,size); nb = size; } } bool filled() const { return nb > 0; } }; class REQUEST{ private: const unsigned signlen = SHA256_DIGEST_LENGTH*2; bool valid; char buf[REQ_BUF_SIZE+1]; unsigned offset; unsigned offset_read; bool addsign_was_called; int sendfd (int handle); friend class CONNECT_INFO; public: void append (const char *s, const char marker); void append_name (const char *name); void append_val (PARAM_STRING val); void append_bob (const void *buf, size_t size); void append_vals (PARAM_STRING val); void append_endvalue(); void append_endvvalue(); bool is_endvvalue(bool &err); int checkname (const char *name, char *&retpt); void reset(); REQUEST(); void addsign(); void add (const char *name, int val); void add (const char *name, long val); void add (const char *name, unsigned val); void add (const char *name, bool val); void add (const char *name, const char *val); void add (const char *name, char *val); void add (const char *name, PARAM_STRING val); void add (const char *name, const std::string &val); void add (const char *name, const BOB_TYPE &val); void add (const char *name, const std::vector> &vals); void add (const char *name, const std::vector &vals); void add (const char *name, const std::vector &vals); void add (const char *name, const PARAM_VECTOR_STRING vals); void add (const char *name, const std::vector &vals); void add (const char *name, const std::vector &vals); void add (const char *name, const std::vector &vals); void add (const char *name, const std::vector &vals); template void add (const char *name, const T val){ add (name,(unsigned)val); } template void add (const char *name, const std::vector &vals); template void adduser (const char *name, const T &val); template void adduser (const char *name, const std::vector &vals); void add_timestamp(); bool is_valid() const; void complete(); void sign(const char *secret); void dump(); int send (int handle); int send (class _F_TCPSERVER_V1 *c); int addpart (const char *line); int addpart (const char *line, int len, EXTRABYTES &extra); int addpart (const char *line, int len); int addpart (const char *line, int len, time_t &intruder, const std::string &secret); int addpartfile (const char *line); unsigned getlength() const ; const char *getbuf() const ; int checksign (const char *secret); int getarg (const char *name, const char *&val); int getarg (const char *name, std::string &val); int getarg (const char *name, int &val); int getarg (const char *name, long &val); int getarg (const char *name, unsigned &val); int getarg (const char *name, bool &val); int getarg (const char *name, BOB_TYPE &val); int getarg (const char *name, unsigned long long &val); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector > &vals); int getarg (const char *name, std::vector &vals); template int getarg (const char *name, T &val); template int getarg (const char *name, std::vector &vals); template int getarguser (const char *name, T &val); template int getarguser (const char *name, std::vector &vals); int write (FILE *fout); template int write(T *fout); bool is_all_read() const; }; int request_splitline(char *buf, unsigned offset, std::function f); template int REQUEST::write(T *fout) { int ret = -1; complete(); if (valid){ ret = request_splitline (buf,offset,[fout](const char *buf, unsigned len){return fout->write(buf,len);}); } return ret; } template int REQUEST::getarg(const char *name, T &val) { int ret = -1; const char *valstr; if (getarg(name,valstr)==0){ const char *pt = valstr; if (isdigit(*pt)){ pt++; while (isdigit(*pt)) pt++; if (*pt == '\0'){ val = (T)atoi(valstr); ret = 0; } } } return ret; } template int REQUEST::getarg(const char *name, std::vector &vals) { int ret = -1; std::vector valss; if (getarg (name,valss)!=-1){ ret = 0; for (auto x:valss){ const char *pt = x; if (isdigit(*pt)){ while (isdigit(*pt)) pt++; if (*pt == '\0'){ vals.push_back((T)atoi(x)); }else{ ret = -1; break; } } } } return ret; } template void REQUEST::add (const char *name, const std::vector &vals) { append_name (name); for (auto x:vals){ char tmp[100]; snprintf (tmp,sizeof(tmp)-1,"%u",x); append_vals(tmp); } append_endvalue(); } template void REQUEST::adduser (const char *name, const T &val) { append_name (name); val.add (*this); } template void REQUEST::adduser (const char *name, const std::vector &vals) { append_name (name); for (auto &x:vals){ x.add (*this); } append_endvvalue(); } template int REQUEST::getarguser (const char *name, T &val) { int ret = -1; char *pt; if (checkname(name,pt)!=-1){ ret = val.getarg (*this); } return ret; } template int REQUEST::getarguser (const char *name, std::vector &vals) { int ret = -1; char *pt; if (checkname(name,pt)!=-1){ ret = 0; bool err = false; while (!is_endvvalue(err) && !err){ T o; if (o.getarg(*this)==-1){ ret = -1; break; }else{ vals.push_back(o); } } if (err) ret = -1; } return ret; } class REQUEST_JSON{ private: bool valid; char buf[REQ_BUF_SIZE+1]; unsigned offset; unsigned offset_read; bool first; void append_comma(); bool expect (const char car); public: void append (const char s); void append (const char *s); void append_name (const char *name); void append_val (PARAM_STRING val); void append_bob (const void *buf, size_t size); void append_vals (PARAM_STRING val); int checkname (const char *name, const char *&retpt); void reset(); REQUEST_JSON(); void add (const char *name, int val); void add (const char *name, long val); void add (const char *name, unsigned val); void add (const char *name, bool val); void add (const char *name, const char *val); void add (const char *name, char *val); void add (const char *name, PARAM_STRING val); void add (const char *name, const std::string &val); void add (const char *name, const BOB_TYPE &val); void add (const char *name, const std::vector> &vals); void add (const char *name, const std::vector &vals); void add (const char *name, const std::vector &vals); void add (const char *name, const PARAM_VECTOR_STRING vals); void add (const char *name, const std::vector &vals); void add (const char *name, const std::vector &vals); void add (const char *name, const std::vector &vals); void add (const char *name, const std::vector &vals); template void add (const char *name, const T val){ add (name,(unsigned)val); } template void add (const char *name, const std::vector &vals); template void add (const char *name, const std::vector> &vals); template void adduser (const char *name, const T &val); template void adduser (const char *name, const std::vector &vals); void add_timestamp(); bool is_valid() const; void complete(); void dump(); int send (BIO *bio); int send (class _F_TCPSERVER_V1 *c); int addpart (const char *line); int addpart (const char *line, int len); int addpartfile (const char *line); unsigned getlength() const ; const char *getbuf() const ; int getarg (const char *name, const char *&val); int getarg (const char *name, std::string &val); int getarg (const char *name, int &val); int getarg (const char *name, long &val); int getarg (const char *name, unsigned &val); int getarg (const char *name, bool &val); int getarg (const char *name, BOB_TYPE &val); int getarg (const char *name, unsigned long long &val); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector &vals); int getarg (const char *name, std::vector > &vals); int getarg (const char *name, std::vector &vals); template int getarg (const char *name, T &val); template int getarg (const char *name, std::vector &vals); template int getarg (const char *name, std::vector> &vals); template int getarguser (const char *name, T &val); template int getarguser (const char *name, std::vector &vals); bool is_all_read() const; }; template int REQUEST_JSON::getarg(const char *name, T &val) { int ret = -1; const char *valstr; if (getarg(name,valstr)==0){ const char *pt = valstr; if (isdigit(*pt)){ pt++; while (isdigit(*pt)) pt++; if (*pt == '\0'){ val = (T)atoi(valstr); ret = 0; } } } return ret; } template int REQUEST_JSON::getarg(const char *name, std::vector &vals) { int ret = -1; std::vector valss; if (getarg (name,valss)!=-1){ ret = 0; for (auto x:valss){ const char *pt = x; if (isdigit(*pt)){ while (isdigit(*pt)) pt++; if (*pt == '\0'){ vals.push_back((T)atoi(x)); }else{ ret = -1; break; } } } } return ret; } template int REQUEST_JSON::getarg(const char *name, std::vector> &vals) { int ret = -1; std::vector> valss; if (getarg (name,valss)!=-1){ ret = 0; for (auto x:valss){ std::vector v; for (auto xx:x){ const char *pt = xx; if (isdigit(*pt)){ while (isdigit(*pt)) pt++; if (*pt == '\0'){ v.push_back((T)atoi(xx)); }else{ ret = -1; break; } } } if (ret == -1) break; vals.push_back(v); } } return ret; } template void REQUEST_JSON::add (const char *name, const std::vector &vals) { append_name (name); append ('['); first = true; for (auto x:vals){ char tmp[100]; snprintf (tmp,sizeof(tmp)-1,"%u",x); append_comma(); append_vals(tmp); } append (']'); } template void REQUEST_JSON::add (const char *name, const std::vector> &vals) { append_name (name); append ('['); first = true; for (auto &x:vals){ append_comma(); append ('['); first = true; for (auto &xx:x){ append_comma(); char tmp[100]; snprintf (tmp,sizeof(tmp)-1,"%u",xx); append_vals(tmp); } append (']'); first = false; } append (']'); } template void REQUEST_JSON::adduser (const char *name, const T &val) { append_name (name); append ('{'); first = true; val.add (*this); append ('}'); first = false; } template void REQUEST_JSON::adduser (const char *name, const std::vector &vals) { append_name (name); append ('['); first = true; for (auto &x:vals){ append_comma(); append ('{'); first = true; x.add (*this); append ('}'); } append (']'); } template int REQUEST_JSON::getarguser (const char *name, T &val) { int ret = -1; const char *pt; if (checkname(name,pt)!=-1 && expect ('{') && val.getarg (*this) != -1 && expect ('}')){ ret = 0; expect (','); // Don't care if there is one , or not } return ret; } template int REQUEST_JSON::getarguser (const char *name, std::vector &vals) { int ret = -1; const char *pt; if (checkname(name,pt) != -1 && expect('[')){ while (offset_read < offset){ if (expect(']')){ expect (','); // Don't care if there is one , or not ret = 0; break; }else if (expect('{')){ T val; if (val.getarg(*this)==-1){ break; }else{ vals.push_back(val); if (!expect('}')){ break; } expect (','); } }else{ break; } } } if (ret != 0){ vals.clear(); } return ret; } class CONNECT_INFO{ EXTRABYTES extra; // When reading an ASYNC response, we may end up with multiple responses // we store the extra bytes here. void copy(const CONNECT_INFO &c); void swap(CONNECT_INFO &&c); bool timeout_seen = false; int timeout = -1; int read_select(void *data, size_t len); public: std::string host; std::string port; std::string bind; std::string secret; int fd; std::vector values; ~CONNECT_INFO(); CONNECT_INFO(); CONNECT_INFO(int _fd); CONNECT_INFO(const CONNECT_INFO &c); CONNECT_INFO & operator = (const CONNECT_INFO &c); CONNECT_INFO(CONNECT_INFO &&c); CONNECT_INFO & operator = (CONNECT_INFO &&c); void close(); void reconnect(); void reset(REQUEST &req); int send (REQUEST &req); int receive(REQUEST &req); int send (const char *command, std::vector &lines); bool has_more() const; void set_timeout(int seconds); bool was_timeout() const; }; class CONNECT_HTTP_INFO{ void copy (const CONNECT_HTTP_INFO &c); void swap (CONNECT_HTTP_INFO &&c); bool timeout_seen = false; int timeout = -1; int read(void *data, size_t len); public: std::string host; std::string port; std::string bind; std::string pageapi; bool use_ssl; bool strictmode; // Validate certificate and hostname BIO *bio; SSL * ssl; ~CONNECT_HTTP_INFO(); CONNECT_HTTP_INFO(); CONNECT_HTTP_INFO(const CONNECT_HTTP_INFO &c); CONNECT_HTTP_INFO &operator= (const CONNECT_HTTP_INFO &c); CONNECT_HTTP_INFO(CONNECT_HTTP_INFO &&c); CONNECT_HTTP_INFO &operator= (CONNECT_HTTP_INFO &&c); int init (PARAM_STRING serverurl); void close(); void reconnect(); void reset(REQUEST_JSON &req); int send (REQUEST_JSON &req); int send (PARAM_STRING s); int write (const void *buf, size_t size); int receive(REQUEST_JSON &req); int receive(void *buf, unsigned size); void setpageapi(PARAM_STRING page); void setnonstrictmode(); void set_timeout(int seconds); bool was_timeout() const; }; struct REQUEST_INFO{ REQUEST req; std::string secret; time_t intruder; REQUEST_INFO(){ intruder = (time_t)0; } int getarg (const char *name, const char *&val){ return req.getarg(name,val); } int getarg (const char *name, std::string &val){ return req.getarg(name,val); } int getarg (const char *name, int &val){ return req.getarg(name,val); } int getarg (const char *name, unsigned &val){ return req.getarg(name,val); } int getarg (const char *name, bool &val){ return req.getarg(name,val); } int getarg (const char *name, BOB_TYPE &val){ return req.getarg(name,val); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } template int getarg (const char *name, T &val){ return req.getarg(name,val); } template int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } template int getarguser (const char *name, T &val){ return req.getarguser(name,val); } template int getarguser (const char *name, std::vector &vals){ return req.getarguser(name,vals); } int addpart (const char *line); int addpart (const char *line, int len); void reset(){ req.reset(); } bool is_all_read() const{ return req.is_all_read(); } }; struct REQUEST_JSON_INFO{ REQUEST_JSON req; REQUEST_JSON_INFO(){ } int getarg (const char *name, const char *&val){ return req.getarg(name,val); } int getarg (const char *name, std::string &val){ return req.getarg(name,val); } int getarg (const char *name, int &val){ return req.getarg(name,val); } int getarg (const char *name, unsigned &val){ return req.getarg(name,val); } int getarg (const char *name, bool &val){ return req.getarg(name,val); } int getarg (const char *name, BOB_TYPE &val){ return req.getarg(name,val); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } template int getarg (const char *name, T &val){ return req.getarg(name,val); } template int getarg (const char *name, std::vector &vals){ return req.getarg(name,vals); } template int getarg (const char *name, std::vector> &vals){ return req.getarg(name,vals); } template int getarguser (const char *name, T &val){ return req.getarguser(name,val); } template int getarguser (const char *name, std::vector &vals){ return req.getarguser(name,vals); } int addpart (const char *line); int addpart (const char *line, int len); void reset(){ req.reset(); } bool is_all_read() const { return req.is_all_read(); } }; int fdpass_receivefd(int sock); int fdpass_sendfd(int sock, int fd); int fdpass_splitbind (const char *s, SSTRING &name, SSTRING &port, SSTRING &logical_name); int fdpass_splitbind (const char *s, SSTRING &name, SSTRING &port); int fdpass_splitbind (const char *s, std::string &name, std::string &port, std::string &logical_name); int fdpass_splitbind (const char *s, std::string &name, std::string &port); int fdpass_sendfd2proxy (int fd1, int fd2, int fd_control, const char *description); int fdpass_tcpconnect (const char *host, const char *port); int fdpass_tcpconnect (const char *bind, bool transparent_mode, const char *host, const char *port); int fdpass_waitdata (int fd); int fdpass_okdata (int fd); void fdpass_closeall (int except_fd1, int except_fd2, int except_fd3); void fdpass_loop(int fd1, int fd2, int do_not_close); struct DATEASC{ char buf[40]; DATEASC(){ buf[0] = '\0'; } }; void fdpass_asctime (time_t t, DATEASC &dst); void fdpass_checkservice (const char *unixsocket); #include #include #include int fdpass_setcontrol (TCPSERVER_V1 &o, const char *control, const char *user); int fdpass_checksign (const char *line, const char *signature); int fdpass_valid_secret ( const std::string &secret, const char *line, std::vector &words, int &n); int fdpass_valid_secret ( const std::map &secrets, const char *host, const char *line, std::vector &words, int &n); void fdpass_shasum (const char *buf1, int lenbuf1, const char *buf2, int lenbuf2, char out[SHA256_DIGEST_LENGTH*2+1]); void fdpass_shasum (const char *line, char out[SHA256_DIGEST_LENGTH*2+1]); void fdpass_makesalt (char out[32+1]); void fdpass_send (struct _F_TCPSERVER_V1 *c, const std::string &secret, const char *line); void fdpass_send (_F_TCPSERVER_V1 *c, const std::string &host, const std::map &secrets, const char *line); void fdpass_sendf (_F_TCPSERVER_V1 *c, const std::string &secret, const char *ctl, ...); void fdpass_sendf (_F_TCPSERVER_V1 *c, const std::string &host, const std::map &secrets, const char *ctl, ...); int fdpass_sendto (int fd, const std::string &secret, const char *line); int fdpass_sendto (int fd, const std::string &host, const std::map &secrets, const char *line); int fdpass_sendtof (int fd, const std::string &secret, const char *ctl, ...); int fdpass_sendtof (int fd, const std::string &host, const std::map &secrets, const char *ctl, ...); int fdpass_sendmaster (int fd, bool is_far); int fdpass_sendmaster (const std::string &host, const std::map &secrets, int fd, bool is_far); bool fdpass_protocheck (const char *line, std::string &newline); bool fdpass_isbadchar (const char car); void fdpass_format_intruder (time_t intrudetime, char intruder[100]); void fdpass_readsecret (const char *secretfile, std::string &mysecret); void fdpass_readsecrets(const char *secretfile, std::map &secrets); std::string fdpass_findsecret (const std::map &secrets, const std::string &host); int fdpass_validstr(const char *s, std::string &v); int fdpass_validbool(const char *s, bool &v); int fdpass_validint(const char *s, int &v); int fdpass_validuns(const char *s, unsigned &v); long long fdpass_getnow(); void fdpass_set_force_addr(PARAM_STRING addr); const char * fdpass_get_force_addr(); int fdpass_sendmail ( PARAM_STRING mailserv, PARAM_STRING mailport, PARAM_STRING from, PARAM_STRING addr, PARAM_STRING subject, PARAM_STRING body); inline bool fdpass_is_all_digit(const char *pt) { bool ret = false; if (isdigit(*pt)){ pt++; while (isdigit(*pt)) pt++; ret = *pt == '\0'; } return ret; } #endif