#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fdpass.h" #include #include using namespace std; static DEBUG_KEY D_CONPROXY ("conproxy","conproxy protocol"); static DEBUG_KEY D_FINDPROC ("findproc","findproc service"); static DEBUG_KEY D_SIGN ("sign","Protocol secret/signature validation"); DEBUG_KEY D_EXTRA("extra","extra communication stuff"); /* * Send a file descriptor to another process using unix domain socket */ int fdpass_sendfd(int sock, int fd) { char bufctl[sizeof(struct cmsghdr)+1*sizeof(int)]; struct cmsghdr *c = (struct cmsghdr*)bufctl; c->cmsg_len = sizeof(bufctl); c->cmsg_level = SOL_SOCKET; c->cmsg_type = SCM_RIGHTS; int *fds = (int*)CMSG_DATA(c); fds[0] = fd; struct msghdr h; struct iovec iov[1]; char buf[1000]; strcpy (buf,"hellohello"); iov[0].iov_base = buf; iov[0].iov_len = 10; h.msg_name = 0; h.msg_namelen = 0; h.msg_iov = iov; h.msg_iovlen = 1; h.msg_control = (void*)bufctl; h.msg_controllen = sizeof(bufctl); h.msg_flags = 0; int ret = sendmsg (sock,&h,0); if (ret==-1){ perror ("sendmsg"); } return ret; } /* Wait to receive a file handle Return the file handle or -1. */ int fdpass_receivefd(int acl_fd) { int ret = -1; char bufctl[sizeof(struct cmsghdr)+1*sizeof(int)]; memset (bufctl,-1,sizeof(bufctl)); struct iovec iov[1]; char buf[1000]; iov[0].iov_base = buf; iov[0].iov_len = sizeof(buf); struct msghdr h; h.msg_name = 0; h.msg_namelen = 0; h.msg_iov = iov; h.msg_iovlen = 1; h.msg_control = bufctl; h.msg_controllen = sizeof(bufctl); struct cmsghdr *c = (struct cmsghdr*) bufctl; c->cmsg_len = sizeof(bufctl); //c->cmsg_level = SOL_SOCKET; //c->cmsg_type = SCM_RIGHTS; h.msg_flags = 0; int len = recvmsg (acl_fd,&h,0); if (len<=0){ perror ("recvmsg"); }else{ #if 0 fprintf (stderr,"message recu flags %d len %d %d %u\n" ,h.msg_flags,len ,h.msg_controllen,sizeof(bufctl)); fprintf (stderr,"iov.len %d\n",iov[0].iov_len); buf[len] = '\0'; fprintf (stderr,"buf = :%s:\n",buf); fprintf (stderr,"msg_len %d msg_level %d msg_type %d\n" ,c->cmsg_len ,c->cmsg_level ,c->cmsg_type); #endif /* On kernel 2.2, we can check c->cmsg_type and c->cmsg_level to find out if there is a file handle On kernel 2.0, we can only tell if there is a descriptor if it is != -1 if (c->cmsg_level == SOL_SOCKET && c->cmsg_type == SCM_RIGHTS){ */ int *fd = (int*)CMSG_DATA(c); //fprintf (stderr,"fd passing %d\n",fd[0]); ret = fd[0]; } return ret; } int fdpass_splitbind (const char *s, SSTRING &name, SSTRING &port, SSTRING &logical_name) { int ret = -1; const char *comma = strchr(s,','); if (comma == NULL){ tlmp_error ("No comma found in bind definition: %s\n",s); }else{ name.setfrom(s,comma-s); comma++; const char *portstart = comma; comma = strchr(portstart,','); if (comma == NULL){ port = portstart; }else{ port.setfrom (portstart,comma-portstart); logical_name = comma+1; } ret = 0; } return ret; } int fdpass_splitbind (const char *s, string &name, string &port, string &logical_name) { SSTRING sname,sport,slname; int ret = fdpass_splitbind (s,sname,sport,slname); if (ret != -1){ name = sname.c_str(); port = sport.c_str(); logical_name = slname.c_str(); } return ret; } int fdpass_splitbind (const char *s, SSTRING &name, SSTRING &port) { SSTRING logical_name; int ret = fdpass_splitbind (s,name,port,logical_name); if (ret != -1 && logical_name.is_filled()){ tlmp_error ("Invalid ip,port definition, logical name discarded: %s\n",s); ret = -1; } return ret; } int fdpass_splitbind (const char *s, string &name, string &port) { SSTRING sname,sport; int ret = fdpass_splitbind (s,sname,sport); if (ret != -1){ name = sname.c_str(); port = sport.c_str(); } return ret; } static const char *conproxy_port = "/var/run/blackhole/conproxy.sock"; static bool errormsg_shown = false; void fdpass_setarg (_F_tlmpprogram___v2 *c) { c->setarg (' ',"conproxyport","Unix socket to connect to the conproxy server",conproxy_port,false); } int fdpass_sendfd2proxy (int fd1, int fd2, int fd_control, const char *description) { if (conproxy_port[0] == '\0' || strcmp(conproxy_port,"none")==0) return -1; glocal int ret = -1; glocal const char *desc = description; glocal int fd1 = fd1; glocal int fd2 = fd2; glocal int fd_control = fd_control; ("unix:",conproxy_port,1); sendf ("newconnection %s\n",glocal.desc); debug_printf (D_CONPROXY,"Receive: %s\n",line); if (strcmp(line,"Go1")==0){ if (fdpass_sendfd (info.handle,glocal.fd1)==-1){ tlmp_error ("Can't send the first handle to the conproxy server\n"); end = true; } }else if (strcmp(line,"Go2")==0){ if (fdpass_sendfd (info.handle,glocal.fd2)==-1){ tlmp_error ("Can't send the second handle to the conproxy server\n"); }else{ glocal.ret = 0; } }else if (strcmp(line,"Go3")==0){ if (fdpass_sendfd (info.handle,glocal.fd_control)==-1){ tlmp_error ("Can't send the control handle to the conproxy server\n"); }else{ glocal.ret = 0; } }else if (strcmp(line,"Ok")==0){ end = true; } if (glocal.ret == -1 && !errormsg_shown){ errormsg_shown = true; tlmp_error ("Can't connect to the conproxy server (%s)\n",conproxy_port); } return glocal.ret; } int fdpass_tcpconnect (const char *bind, bool transparent_mode, const char *host, const char *port) { if (port[0] == '/'){ host = "unix:"; } int fd = cmdsock_connect (bind,transparent_mode,host,port,5,1); if (fd != -1){ int opt = 1; setsockopt (fd,SOL_TCP,TCP_NODELAY,&opt,sizeof(opt)); }else{ tlmp_error ("Can't connect to host %s, port %s (bind=%s transparent_mode=%d) (%s)\n" ,host,port,bind,transparent_mode,strerror(errno)); } return fd; } int fdpass_tcpconnect (const char *host, const char *port) { return fdpass_tcpconnect (NULL,false,host,port); } int fdpass_tcpconnect_async (const char *host, const char *port) { return cmdsock_connect_async (nullptr,host,port); } /* Wait a confirmation from the horizon server that we can switch to data mode (payload) */ int fdpass_waitdata(int fd) { int ret = -1; char buf[5]; if (read(fd,buf,5) == 5 && memcmp(buf,"data\n",5)==0) ret = 0; return ret; } /* Confirm to the blackhole it can now start sending data. */ int fdpass_okdata(int fd) { int opt = 1; setsockopt (fd,SOL_TCP,TCP_NODELAY,&opt,sizeof(opt)); return write (fd,"data\n",5)==5; } /* Close all connection in a TCPSERVER except two */ void fdpass_closeall (int except_fd1, int except_fd2, int except_fd3, int except_fd4) { for (int fd=3; fd<1024; fd++){ // debug_printf (D_CONPROXY,"closeall %d %d %d %d %d\n",fd,except_fd1,except_fd2,except_fd3,except_fd4); if (fd != except_fd1 && fd != except_fd2 && fd != except_fd3 && fd != except_fd4) close (fd); } } #define PREREAD_SIZE (64*1024) /* This is a loop that copies back and forth between fd1 and fd2. If fdcheck != -1, then a protocol checker is involved. Here is how the protocol checker works -All data received from fd1 (the client), is buffered in the preread buffer. -It is also sent to the protocol checker. -If it exceeds the buffer size, it means there is something wrong either with the protocol checker, or tne input data itself. The loop stops listening on fd1. -If the protocol checker just close the connection, the loop ends and all connections are closed. -The protocol checker sends back PROTOCHECK blocks. A block contains a command and an offset. Here are the commands: SEND:offset The loop is allowed to send stuff up to the offset to fd2. FAIL The loop close the connections. GO The loop continue without the protocol checker. */ void fdpass_loop( int fd1, // Copy back and forth between fd1 and fd2 int fd2, // in non-blocking mode int fdcheck, // Protocol validator int do_not_close) // Do not close this handle. When the process will end // it will close and the parent will learn it is done. { fdpass_closeall (fd1,fd2,fdcheck,do_not_close); // The connection proxy is not running, so we handle the // the job here. glocal int fd1 = fd1; glocal int fd2 = fd2; glocal int fdcheck = fdcheck; glocal long long offset = 0; glocal int nb_preread = 0; glocal char preread[PREREAD_SIZE*2]; //glocal vector debug; if (0){ ("/tmp/fdpass.log",true); fprintf (fout,"%d %d %d %d\n",getpid(),glocal.fd1,glocal.fd2,glocal.fdcheck); return 0; } (); if (no == glocal.fd1){ glocal.fd1 = -1; unsigned long size; long long last; if (glocal.fd2 == -1 || !is_blocked(glocal.fd2,size,last)){ endserver = true; } }else if (no == glocal.fd2){ glocal.fd2 = -1; unsigned long size; long long last; if (glocal.fd1 == -1 || !is_blocked(glocal.fd1,size,last)){ endserver = true; } }else if (no == glocal.fdcheck){ endserver = true; } if (no == glocal.fd1){ if (glocal.fdcheck != -1){ int newsize = glocal.nb_preread + info.linelen; memcpy (glocal.preread+glocal.nb_preread,line,info.linelen); glocal.nb_preread = newsize; sendto (glocal.fdcheck,line,info.linelen); if (newsize > PREREAD_SIZE) setlisten (no,false); }else if (glocal.fd2 != -1){ sendto (glocal.fd2,line,info.linelen); } }else if (no == glocal.fdcheck){ if (strcmp(line,"GO")==0){ if (glocal.nb_preread > 0 && glocal.fd2 != -1) sendto (glocal.fd2,glocal.preread,glocal.nb_preread); endclient = true; glocal.fdcheck = -1; }else if (strcmp(line,"FAIL")==0){ endserver = true; }else if (strncmp(line,"SEND:",5)==0){ long long upto = atoll(line+5); int inbuffer = upto - glocal.offset; if (inbuffer < 0){ tlmp_error ("fdpass_loop: upto too small %Ld > %Ld\n",glocal.offset,upto); }else if (inbuffer > 0){ if (inbuffer > glocal.nb_preread){ tlmp_error ("fdpass_loop: upto too large %Ld > %Ld\n",upto,glocal.offset+glocal.nb_preread); }else{ int old_nb_preread = glocal.nb_preread; if (glocal.fd2 != -1) sendto (glocal.fd2,glocal.preread,inbuffer); glocal.nb_preread -= inbuffer; glocal.offset += inbuffer; if (glocal.nb_preread > 0){ memmove (glocal.preread,glocal.preread+inbuffer,glocal.nb_preread); } if (glocal.nb_preread <= PREREAD_SIZE && old_nb_preread > PREREAD_SIZE){ setlisten (glocal.fd1,true); } } } } }else{ if (glocal.fd1 != -1) sendto (glocal.fd1,line,info.linelen); } int other=-1; if (no == glocal.fd1){ other = glocal.fd2; }else if (no == glocal.fd2){ other = glocal.fd1; }else if (no == glocal.fdcheck){ other = glocal.fd1; } // glocal.debug.push_back(string_f("event no=%d other=%d\n",no,other)); if (ev == TCPSERVER_OUTFULL){ debug_printf (D_CONPROXY,"handle %d blocked, stop listening to %d\n",no,other); setlisten (other,false); }else if (ev == TCPSERVER_OUTOK){ debug_printf (D_CONPROXY,"handle %d flowing again, resume listening to %d\n",no,other); setlisten (other,true); }else if (ev == TCPSERVER_OUTFLUSHED){ if (glocal.fd1 == -1 || glocal.fd2 == -1){ debug_printf (D_CONPROXY,"Late closing connection %d, ending loop\n",no); endserver = true; } } o.setrawmode (true); o.setnonblock (true,100000); int opt = 1; setsockopt (fd1,SOL_TCP,TCP_NODELAY,&opt,sizeof(opt)); setsockopt (fd2,SOL_TCP,TCP_NODELAY,&opt,sizeof(opt)); o.inject (fd1); o.inject (fd2); if (fdcheck != -1){ setsockopt (fdcheck,SOL_TCP,TCP_NODELAY,&opt,sizeof(opt)); o.inject(fdcheck); o.setrawmode (fdcheck,false); } o.loop(); //if (glocal.debug.size() > 0){ // ("/tmp/fdpass.log",true); // // for (auto &s:glocal.debug){ // fprintf (fout,"%d %s\n",getpid(),s.c_str()); // } // return 0; // // //} } void fdpass_loop( int fd1, // Copy back and forth between fd1 and fd2 int fd2, // in non-blocking mode int do_not_close) // Do not close this handle. When the process will end // it will close and the parent will learn it is done. { fdpass_loop (fd1,fd2,-1,do_not_close); } /* Convert a time_t into a string localtime */ void fdpass_asctime (time_t t, DATEASC &dst) { if (t == (time_t)0){ strcpy (dst.buf,"----/--/--_--:--:--"); }else{ struct tm *tt = localtime (&t); snprintf (dst.buf,sizeof(dst.buf),"%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); } } /* Check if a server is listening on that unix port. Exits it there is one. This avoids starting the daemon twice (while thinking you are using the utility-control program). */ void fdpass_checkservice (const char *unixpath) { ("unix:",unixpath,5); fprintf (stderr,"Service is already started, ending\n"); exit (-1); } /* Get more information about a socket using the findproc service Return -1 if there is no information */ int fdpass_findproc ( const char *unixpath, const char *from, const char *from_port, const char *to, const char *to_port, string &process, string &uid, string &gid, string &xid, string &env) { glocal int ret = -1; glocal char request[100]; glocal string *process = &process; glocal string *uid = &uid; glocal string *gid = &gid; glocal string *xid = &xid; glocal string *env = &env; snprintf (glocal.request,sizeof(glocal.request)-1,"%s %s %s %s",from,from_port,to,to_port); debug_printf (D_FINDPROC,"connect to %s\n",unixpath); ("unix:",unixpath,5); debug_printf (D_FINDPROC,"Send ident %s\n",glocal.request); sendf ("ident %s\n",glocal.request); debug_printf (D_FINDPROC,"Receive %s\n",line); if (strncmp(line,"name ",5)==0){ (*glocal.process) = line+5; }else if (strncmp(line,"xid ",4)==0){ (*glocal.xid) = line+4; }else if (strncmp(line,"env ",4)==0){ (*glocal.env) = line+4; }else if (strncmp(line,"user ",5)==0){ (*glocal.uid) = line+5; }else if (strncmp(line,"group ",6)==0){ (*glocal.gid) = line+6; }else if (strcmp(line,"OK")==0){ glocal.ret = 0; end = true; } tlmp_error ("Can't connect to findproc service\n"); return glocal.ret; } /* Opens a control unix socket for the service */ int fdpass_setcontrol (TCPSERVER_V1 &o, const char *control, const char *user) { int ret = 0; SSTRING tmp; tmp.setfromf ("unix:%s",control); if (o.listen("",tmp.c_str())==-1){ tlmp_error ("Can't setup the control socket %s (%s)\n" ,control,strerror(errno)); ret = -1; }else if (user != NULL){ struct passwd *u = getpwnam(user) ; if (u == NULL){ tlmp_error ("Error retrieving %s uid/gid\n",user) ; ret = -1; }else{ chown(control, u->pw_uid, u->pw_gid) ; chmod(control, 0770) ; } } return ret; } static void fdpass_shasum (const char *line, char out[SHA256_DIGEST_LENGTH*2+1]) { EVP_MD_CTX *ctx = EVP_MD_CTX_new(); EVP_DigestInit_ex(ctx,EVP_sha256(),nullptr); EVP_DigestUpdate(ctx,line,strlen(line)); unsigned char bufout[BUFSIZ]; unsigned int size=0; EVP_DigestFinal_ex(ctx,bufout,&size); EVP_MD_CTX_free(ctx); char *ptout = out; for (unsigned j = 0; j < size; j++){ sprintf(ptout,"%02x", bufout[j]); ptout += 2; } } /* Compute the sha256 sum of a line and checks if it match the signature */ int fdpass_checksign (const char *line, const char *signature) { char out[SHA256_DIGEST_LENGTH*2+1]; fdpass_shasum (line,out); return strcmp(signature,out); } /* Protocol lines are built this way command arg1 arg2 ... salt signature The salt is a string built using random characters concatenated with the timeofday (microseconds). This produces an unpredictable salt. The signature is an sha256 sum of the line up to the signature + the secret */ int fdpass_valid_secret ( const string &secret, const char *line, // The original protocol line vector &words, // Each words in the line int &n) // Number of words in the line // If there is salt and signature, 2 will be substract // The caller does not know about salt and signature { int ret = -1; if (secret.size() == 0){ // Secret mode not active ret = 0; }else{ if (n > 2){ const char *signature = words[n-1].c_str(); string line0 = string(line,strlen(line)-strlen(signature)) + secret; if (fdpass_checksign(line0.c_str(),signature)==0){ ret = 0; } debug_printf (D_SIGN,"REC: %s\nTST: %s\nSIG: %s ret=%d\n",line,line0.c_str(),signature,ret); } n-=2; } return ret; } int fdpass_valid_secret ( const map &secrets, const char *host, const char *line, // The original protocol line vector &words, // Each words in the line int &n) // Number of words in the line // If there is salt and signature, 2 will be substract // The caller does not know about salt and signature { int ret = -1; if (secrets.size()==0){ // Secret mode not active ret = 0; }else{ map::const_iterator it = secrets.find(host); if (it == secrets.end()){ tlmp_error ("No secret for host %s\n",host); }else{ ret = fdpass_valid_secret (it->second,line,words,n); } } return ret; } void fdpass_makesalt (char out[32+1]) { static int fd = -1; if (fd == -1){ fd = open ("/dev/urandom",O_RDONLY,0); if (fd == -1){ tlmp_error ("Can't open /dev/uramdom (%s), can't continue\n",strerror(errno)); exit (-1); } } char buf[8]; int n = read (fd,buf,8); if (n != 8){ tlmp_error ("can't read /dev/uandom (%s), can't continue",strerror(errno)); exit (-1); } sprintf (out,"%02x%02x%02x%02x%02x%02x%02x%02x",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); struct timeval tv; if (gettimeofday(&tv,NULL)==-1){ tlmp_error ("Can't get timeofday, ending (%s)\n",strerror(errno)); exit (-1); } sprintf (out+16,"%08lx%08lx",(unsigned long)tv.tv_sec,(unsigned long)tv.tv_usec); } PROTOSTR PROTO_REJECT("reject %s"); PROTOSTR PROTO_CONNECT_LINK("connect %s %s %s %s %s %s"); /* Send a message to a blackhole component, adding optionnally a signature */ void fdpass_send (_F_TCPSERVER_V1 *c, const string &secret, const char *line) { if (secret.size()==0){ c->send (line); c->send ("\n"); }else{ char salt[33]; fdpass_makesalt(salt); string buf = string(line) + " " + salt + " "; c->send (buf.c_str()); buf += secret; char out[SHA256_DIGEST_LENGTH*2+1]; fdpass_shasum (buf.c_str(),out); c->send (out); c->send ("\n"); } } void fdpass_send (_F_TCPSERVER_V1 *c, const string &host, const map &secrets, const char *line) { if (secrets.size() == 0){ static string empty; fdpass_send (c,empty,line); }else{ map::const_iterator it=secrets.find(host); if (it == secrets.end()){ tlmp_error ("Can't send message to host %s, no secret defined: %s\n",host.c_str(),line); }else{ fdpass_send (c,it->second,line); } } } void fdpass_sendf (_F_TCPSERVER_V1 *c, const string &secret, const char *ctl, ...) { char line[1000]; va_list list; va_start (list,ctl); vsnprintf (line,sizeof(line)-1,ctl,list); va_end (list); fdpass_send (c,secret,line); } void fdpass_sendf (_F_TCPSERVER_V1 *c, const string &host, const map &secrets, const char *ctl, ...) { char line[1000]; va_list list; va_start (list,ctl); vsnprintf (line,sizeof(line)-1,ctl,list); va_end (list); if (secrets.size() == 0){ static string empty; fdpass_send (c,empty,line); }else{ map::const_iterator it=secrets.find(host); if (it == secrets.end()){ tlmp_error ("Can't send message to host %s, no secret defined: %s\n",host.c_str(),line); }else{ fdpass_send (c,it->second,line); } } } void fdpass_sendf (_F_TCPSERVER_V1 *c, const string &host, const map &secrets, const PROTOSTR &ctl, ...) { char line[1000]; va_list list; va_start (list,ctl); vsnprintf (line,sizeof(line)-1,ctl.c_str(),list); va_end (list); if (secrets.size() == 0){ static string empty; fdpass_send (c,empty,line); }else{ map::const_iterator it=secrets.find(host); if (it == secrets.end()){ tlmp_error ("Can't send message to host %s, no secret defined: %s\n",host.c_str(),line); }else{ fdpass_send (c,it->second,line); } } } void fdpass_sendtof (int fd, const string &host, const map &secrets, const PROTOSTR &ctl, ...) { char line[1000]; va_list list; va_start (list,ctl); vsnprintf (line,sizeof(line)-1,ctl.c_str(),list); va_end (list); if (secrets.size() == 0){ static string empty; fdpass_sendto (fd,empty,line); }else{ map::const_iterator it=secrets.find(host); if (it == secrets.end()){ tlmp_error ("Can't send message to host %s, no secret defined: %s\n",host.c_str(),line); }else{ fdpass_sendto (fd,it->second,line); } } } void fdpass_sendf (const string &host, const char *port, const map &secrets, const PROTOSTR &ctl, ...) { if (fork()==(pid_t)0){ char line[1000]; va_list list; va_start (list,&ctl); vsnprintf (line,sizeof(line)-1,ctl.c_str(),list); va_end (list); int fd = fdpass_tcpconnect (host.c_str(),port); if (fd == -1){ tlmp_error ("Can't connect to host %s, port %s\n",host.c_str(),port); }else{ if (secrets.size() == 0){ static string empty; fdpass_sendto (fd,empty,line); }else{ map::const_iterator it=secrets.find(host); if (it == secrets.end()){ tlmp_error ("Can't send message to host %s, no secret defined: %s\n",host.c_str(),line); }else{ fdpass_sendto (fd,it->second,line); } } } _exit (0); } } void fdpass_sendto (int fd, const string &secret, const char *line) { if (secret.size()==0){ write (fd,line,strlen(line)); write (fd,"\n",1); }else{ char salt[33]; fdpass_makesalt(salt); string buf = string(line) + " " + salt + " "; write (fd,buf.c_str(),buf.size()); buf += secret; char out[SHA256_DIGEST_LENGTH*2+1]; fdpass_shasum (buf.c_str(),out); write (fd,out,SHA256_DIGEST_LENGTH*2); write (fd,"\n",1); } } void fdpass_sendto (int fd, const string &host, const map &secrets, const char *line) { if (secrets.size() == 0){ static string empty; fdpass_sendto (fd,empty,line); }else{ map::const_iterator it=secrets.find(host); if (it == secrets.end()){ tlmp_error ("Can't send message to host %s, no secret defined: %s\n",host.c_str(),line); }else{ fdpass_sendto (fd,it->second,line); } } } void fdpass_sendtof (int fd, const string &secret, const char *ctl, ...) { char line[1000]; va_list list; va_start (list,ctl); vsnprintf (line,sizeof(line)-1,ctl,list); va_end (list); fdpass_sendto (fd,secret,line); } void fdpass_sendtof (int fd, const string &host, const map &secrets, const char *ctl, ...) { char line[1000]; va_list list; va_start (list,ctl); vsnprintf (line,sizeof(line)-1,ctl,list); va_end (list); fdpass_sendto (fd,host,secrets,line); } /* Send the "master" command to the horizon server */ int fdpass_sendmaster (int fd, bool is_far) { char buf[100]; int n = snprintf (buf,sizeof(buf)-1,"master %s %s\n" ,is_far ? "far" : "near" ,PROTOCOL_VERSION); int ret = 0; if (write (fd,buf,n)!=n){ ret = -1; tlmp_error ("Can't send master command to horizon\n"); } return ret; } int fdpass_sendmaster (const string &host, const map &secrets, int fd, bool is_far) { int ret = -1; if (secrets.size()==0){ ret = fdpass_sendmaster (fd,is_far); }else{ fdpass_sendtof (fd,host,secrets,"master %s %s ",is_far ? "far" : "near",PROTOCOL_VERSION); ret = 0; } return ret; } static const char *badchar = "\"'`();*?"; /* Check if a protocol line do not contain bad character (dangourous for scripting) */ bool fdpass_protocheck (const char *line, string &newline) { bool ret = true; if (strlen(line)>250){ newline = string(line,250); ret = false; }else{ while (*badchar != '\0'){ if (strchr(line,*badchar)!=NULL){ newline = line; ret = false; break; } badchar++; } } return ret; } /* Check if this char is a member of the badchar set */ bool fdpass_isbadchar (const char car) { return strchr(badchar,car)!=NULL; } /* Format the intruder time */ void fdpass_format_intruder (time_t intrudetime, char intruder[100]) { intruder[0] = '\0'; if (intrudetime != 0){ DATEASC date; fdpass_asctime (intrudetime,date); snprintf (intruder,100-1," *** Intruder since %s",date.buf); } } /* Read one line in a text file */ void fdpass_readsecret ( const char *secretfile, string &mysecret) { mysecret = ""; if (secretfile != NULL){ glocal string *mysecret = &mysecret; (secretfile,true); line = str_skip(line); if (*line != '\0') *glocal.mysecret = line; return 0; } } void fdpass_readsecrets( const char *secretfile, map &secrets) { secrets.clear(); if (secretfile != NULL){ glocal map *secrets = &secrets; (secretfile,true); const char *pt = str_skip(line); if (*pt != '\0' && *pt != '#'){ string name,secret; pt = str_copyword (name,line); pt = str_copyword(secret,pt); pt = str_skip(pt); if (secret.size() == 0 || *pt != '\0'){ tlmp_error ("File %s, line %d, invalid line\n",info.filename,noline); }else{ (*glocal.secrets)[name] = secret; } } return 0; } } /* Find one secret in a map. If the secret is not there, return an empty string */ string fdpass_findsecret (const map &secrets, const string &host) { string ret; if (secrets.size() > 0){ map::const_iterator it = secrets.find(host); if (it != secrets.end()){ ret = it->second; } } return ret; } #ifdef TEST static void fdpass_shasum_old (const char *line, char out[SHA256_DIGEST_LENGTH*2+1]) { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, line,strlen(line)); unsigned char bufout[BUFSIZ]; SHA256_Final(bufout, &ctx); char *ptout = out; for (unsigned j = 0; j < SHA256_DIGEST_LENGTH; j++){ sprintf(ptout,"%02x", bufout[j]); ptout += 2; } } int main (int argc, char *argv[]) { for (int i=1; i