#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fdpass.h" #include "hostname.h" #include #include using namespace std; static DEBUG_KEY D_SIGN ("sign","Protocol secret/signature validation"); int fdpass_validstr(const char *s, std::string &v) { v = s; return 0; } int fdpass_validbool(const char *s, bool &v) { int ret = -1; if (s!=NULL && (strcmp(s,"0")==0 || strcmp(s,"1")==0)){ v = atoi(s); ret = 0; } return ret; } int fdpass_validint(const char *s, int &v) { int ret = 0; if (s != NULL){ const char *pt = s; if (*pt == '-') pt++; if (isdigit(*pt)){ pt++; while (isdigit(*pt)) pt++; if (*pt == '\0'){ v = atoi(s); ret = 0; } } } return ret; } int fdpass_validuns(const char *s, unsigned &v) { int ret = 0; if (s != NULL){ const char *pt = s; if (isdigit(*pt)){ pt++; while (isdigit(*pt)) pt++; if (*pt == '\0'){ v = atoi(s); ret = 0; } } } return ret; } long long fdpass_getnow() { struct timeval tv; if (gettimeofday(&tv,NULL)==-1){ tlmp_error ("Can't get timeofday, ending (%s)\n",strerror(errno)); exit (-1); } return tv.tv_sec*1000000+tv.tv_usec; } /* Convert a time_t into a string localtime */ void fdpass_asctime (time_t t, char dst[20]) { if (t == (time_t)0){ strcpy (dst,"----/--/--_--:--:--"); }else{ struct tm *tt = localtime (&t); snprintf (dst,20,"%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); } } int fdpass_tcpconnect (const char *bind, bool transparent_mode, const char *host, const char *port) { 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); } /* 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; } void fdpass_shasum (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; } } void fdpass_shasum (const char *buf1, int lenbuf1, const char *buf2, int lenbuf2, char out[SHA256_DIGEST_LENGTH*2+1]) { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, buf1,lenbuf1); SHA256_Update(&ctx, buf2,lenbuf2); 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; } } /* 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); } } unsigned 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); } /* 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); } } } int fdpass_sendto (int fd, const string &secret, const char *line) { int ret = -1; if (secret.size()==0){ int len = strlen(line); if (write (fd,line,len)==len && write (fd,"\n",1)==1){ ret = 0; } }else{ char salt[33]; fdpass_makesalt(salt); string buf = string(line) + " " + salt + " "; if (write (fd,buf.c_str(),buf.size())==(int)buf.size()){ buf += secret; char out[SHA256_DIGEST_LENGTH*2+1]; fdpass_shasum (buf.c_str(),out); if (write (fd,out,SHA256_DIGEST_LENGTH*2)==SHA256_DIGEST_LENGTH*2 && write (fd,"\n",1)==1){ ret = 0; } } } return ret; } int fdpass_sendto (int fd, const string &host, const map &secrets, const char *line) { int ret = -1; 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{ ret = fdpass_sendto (fd,it->second,line); } } return ret; } int 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); return fdpass_sendto (fd,secret,line); } int 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); return fdpass_sendto (fd,host,secrets,line); } 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){ char date[20]; fdpass_asctime (intrudetime,date); snprintf (intruder,100-1," *** Intruder since %s",date); } } /* 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; } static const char REQ_ENDREQUEST=1; static const char REQ_ENDNAME=2; static const char REQ_ENDVALUE=3; static const char REQ_ENDVVALUE=4; static const char REQ_EOL=5; static const char REQ_ENDVVEC=6; static const char REQ_LASTMARK=6; void REQUEST::append (const char *s, const char marker) { if (valid){ const char *pt = s; while (*pt != '\0'){ if (*pt <= REQ_LASTMARK){ valid = false; break; } pt++; } if (valid){ int len = pt-s; if (offset + len + 1 < REQ_BUF_SIZE){ strcpy (buf+offset,s); offset += len; buf[offset++] = marker; }else{ valid = false; } } } } void REQUEST::append_name (const char *name){ append (name,REQ_ENDNAME); } void REQUEST::append_val (const char *val) { append (val,REQ_ENDVALUE); } void REQUEST::append_vals (const char *val){ append (val,REQ_ENDVVALUE); } void REQUEST::reset() { offset = 0; offset_read = 0; buf[0] = '\0'; valid = true; addsign_was_called = false; } REQUEST::REQUEST() { reset(); } void REQUEST::addsign() { if (offset != 0){ valid = false; tlmp_error ("REQUEST::addsign must be called before all adds\n"); }else{ addsign_was_called = true; offset += 32 + SHA256_DIGEST_LENGTH*2; } } void REQUEST::add (const char *name, int val) { char tmp[100]; snprintf (tmp,sizeof(tmp),"%d",val); append_name (name); append_val (tmp); } void REQUEST::add (const char *name, unsigned val) { char tmp[100]; snprintf (tmp,sizeof(tmp),"%u",val); append_name (name); append_val (tmp); } void REQUEST::add (const char *name, bool val) { append_name (name); append_val (val ? "1" : "0"); } void REQUEST::add (const char *name, const char *val) { append_name (name); append_val (val); } void REQUEST::add (const char *name, const PARAM_STRING &val) { append_name (name); append_val (val.ptr); } void REQUEST::add (const char *name, const vector> &vals) { append_name (name); for (auto &x:vals){ for (auto &xx:x){ append_vals(xx.c_str()); } append ("",REQ_ENDVALUE); } append ("",REQ_ENDVVEC); } void REQUEST::add (const char *name, const vector &vals) { append_name (name); for (auto &x:vals){ append_vals(x.c_str()); } append ("",REQ_ENDVALUE); } void REQUEST::add (const char *name, const vector &vals) { append_name (name); for (auto x:vals){ append_vals(x); } append ("",REQ_ENDVALUE); } void REQUEST::add (const char *name, const PARAM_VECTOR_STRING vals) { append_name (name); for (auto x:vals){ append_vals(x); } append ("",REQ_ENDVALUE); } void REQUEST::add (const char *name, const vector &vals) { append_name (name); for (auto x:vals){ append_vals(x ? "1" : "0"); } append ("",REQ_ENDVALUE); } void REQUEST::add (const char *name, const vector &vals) { append_name (name); for (auto x:vals){ char tmp[100]; snprintf (tmp,sizeof(tmp)-1,"%d",x); append_vals(tmp); } append ("",REQ_ENDVALUE); } void REQUEST::add (const char *name, const vector &vals) { append_name (name); for (auto x:vals){ char tmp[100]; snprintf (tmp,sizeof(tmp)-1,"%u",x); append_vals(tmp); } append ("",REQ_ENDVALUE); } void REQUEST::add_timestamp() { char tmp[100]; long long now = fdpass_getnow(); snprintf (tmp,sizeof(tmp)-1,"%Ld",now); add ("_time_",tmp); } bool REQUEST::is_valid() const { return valid; } // Put the last tag to end the REQUEST void REQUEST::complete() { append ("",REQ_ENDREQUEST); buf[offset] = '\0'; } void REQUEST::sign(const char *secret) { if (!addsign_was_called){ tlmp_error ("Invalid REQUEST sequence: sign called without addsign\n"); valid = false; }else{ char *salt = buf + signlen; char tmpsalt[32+1]; // memset (tmpsalt,0,sizeof(tmpsalt)); fdpass_makesalt(tmpsalt); // for (unsigned i=0; i REQ_LASTMARK) pt++; if (*pt == REQ_ENDNAME){ int len = pt-start; printf ("param=%*.*s ",len,len,start); pt++; }else if (*pt == REQ_ENDVALUE){ int len = pt-start; printf ("val=%*.*s ",len,len,start); pt++; }else if (*pt == REQ_ENDVVALUE){ int len = pt-start; printf ("%*.*s, ",len,len,start); pt++; if (*pt == REQ_ENDVALUE) pt++; }else if (*pt == REQ_ENDREQUEST){ break; } } printf ("\n"); } int REQUEST::write (FILE *fout) { int ret = -1; complete(); if (valid){ // We split the bloc in lines for (unsigned i=0; i 80) len = 80; unsigned last = i+len; for (unsigned j=i; jsend (buf,offset); }else{ // We send an empty answer anyway REQUEST req; req.complete(); c->send (req.buf,req.offset); } return ret; } // Add a part of a request (received on the socket) // Return -1 if something is wrong // Return 0 if the request is still incomplete // Return 1 if the request is complete, ready to process int REQUEST::addpart (const char *line) { int ret = -1; if (!valid){ ret = -1; }else{ int len = strlen(line); if (len + offset > REQ_BUF_SIZE){ valid = false; }else{ strcpy(buf+offset,line); offset += len; ret = 0; if (buf[offset-1] == REQ_ENDREQUEST) ret = 1; } } return ret; } /* This is like addpart, except the line read came from REQUEST::write. which output the buffer in 80 characters lines and encode the \n as REQ_EOL */ int REQUEST::addpartfile (const char *line) { string tmp(line); for (unsigned i=0; i REQ_LASTMARK) pt++; if (*pt == REQ_ENDNAME){ *pt++ = '\0'; // We end the string there. Clearly, we can walk the buffer once if (strcmp(start,name)==0){ retpt = pt; ret = 0; } } return ret; } int REQUEST::getarg (const char *name, const char *&val) { val = ""; char *pt; int ret = checkname (name,pt); if (ret != -1){ val = pt; const char *end = buf+offset; while (pt < end && *pt > REQ_LASTMARK) pt++; if (*pt == REQ_ENDVALUE){ *pt++ = '\0'; offset_read = pt-buf; ret = 0; } } if (ret != 0) name = ""; return ret; } int REQUEST::getarg (const char *name, int &val) { int ret = -1; const char *valstr; if (getarg(name,valstr)==0){ const char *pt = valstr; if (pt[0] == '-') pt++; if (isdigit(*pt)){ pt++; while (isdigit(*pt)) pt++; if (*pt == '\0'){ val = atoi(valstr); ret = 0; } } } return ret; } int REQUEST::getarg (const char *name, unsigned long long &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 = atoll(valstr); ret = 0; } } } return ret; } int REQUEST::getarg (const char *name, unsigned &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 = atoi(valstr); ret = 0; } } } return ret; } int REQUEST::getarg (const char *name, bool &val) { int ret = -1; const char *valstr; if (getarg(name,valstr)==0){ if (strcmp(valstr,"1")==0){ val = true; ret = 0; }else if (strcmp(valstr,"0")==0){ val = false; ret = 0; } } return ret; } int REQUEST::getarg (const char *name, vector &vals) { char *pt; int ret = checkname(name,pt); if (ret != -1){ const char *end = buf+offset; while (true){ const char *val = pt; while (pt < end && *pt > REQ_LASTMARK) pt++; if (*pt == REQ_ENDVVALUE){ *pt++ = '\0'; vals.push_back(val); }else if (*pt == REQ_ENDVALUE && pt == val){ pt++; ret = 0; break; }else{ break; } } offset_read = pt-buf; } if (ret != 0){ name = ""; vals.clear(); } return ret; } int REQUEST::getarg (const char *name, vector &vals) { char *pt; int ret = checkname(name,pt); if (ret != -1){ const char *end = buf+offset; while (true){ const char *val = pt; while (pt < end && *pt > REQ_LASTMARK) pt++; if (*pt == REQ_ENDVVALUE){ *pt++ = '\0'; vals.push_back(val); }else if (*pt == REQ_ENDVALUE && pt == val){ pt++; ret = 0; break; }else{ break; } } offset_read = pt-buf; } if (ret != 0){ name = ""; vals.clear(); } return ret; } int REQUEST::getarg (const char *name, vector > &vals) { char *pt; int ret = checkname(name,pt); if (ret != -1){ const char *end = buf+offset; vector vvals; while (pt < end && *pt != REQ_ENDVVEC){ const char *val = pt; while (pt < end && *pt > REQ_LASTMARK) pt++; if (*pt == REQ_ENDVVALUE){ *pt++ = '\0'; vvals.push_back(val); }else if (*pt == REQ_ENDVALUE && pt == val){ pt++; vals.push_back(vvals); vvals.clear(); }else{ break; } } if (*pt == REQ_ENDVVEC){ ret = 0; pt++; } offset_read = pt-buf; } if (ret != 0){ name = ""; vals.clear(); } return ret; } int REQUEST::getarg (const char *name, vector &vals) { int ret = -1; vector valss; if (getarg (name,valss)!=-1){ ret = 0; for (auto x:valss){ if (strcmp(x,"0")==0){ vals.push_back(false); }else if (strcmp(x,"1")==0){ vals.push_back(true); }else{ ret = -1; break; } } } return ret; } int REQUEST::getarg (const char *name, vector &vals) { int ret = -1; vector valss; if (getarg (name,valss)!=-1){ ret = 0; for (auto x:valss){ const char *pt = x; if (isdigit(*pt) || (pt[0] == '-' && isdigit(pt[1]))){ pt++; while (isdigit(*pt)) pt++; if (*pt == '\0'){ vals.push_back(atoi(x)); }else{ ret = -1; break; } } } } return ret; } int REQUEST::getarg (const char *name, vector &vals) { int ret = -1; 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(atoi(x)); }else{ ret = -1; break; } } } } return ret; } bool REQUEST::is_all_read() const { bool ret = false; if (offset_read == offset-1 && buf[offset_read] == REQ_ENDREQUEST) ret = true; return ret; } int REQUEST_INFO::addpart (const char *line, int ) { int ret = -1; if (intruder == (time_t)0){ ret = req.addpart(line); if(ret == 1){ if (secret.size() > 0){ if (req.checksign(secret.c_str())==-1){ intruder = time(NULL); ret = -1; } } } } return ret; } CONNECT_INFO::~CONNECT_INFO() { if (fd != -1) close (fd); } CONNECT_INFO::CONNECT_INFO() { fd = -1; } CONNECT_INFO::CONNECT_INFO(int _fd) { fd = _fd; } void CONNECT_INFO::reconnect() { close (fd); if (host.empty()){ fd = fdpass_tcpconnect (NULL,false,"unix:",port.c_str()); }else{ const char *bindstr=NULL; if (bind.size() > 0) bindstr=bind.c_str(); fd = fdpass_tcpconnect (bindstr,false,host.c_str(),port.c_str()); } } void CONNECT_INFO::reset(REQUEST &req) { req.reset(); if (secret.size() > 0) req.addsign(); } int CONNECT_INFO::send (const char *command, vector &lines) { int ret = 0; lines.clear(); string tmp; for (auto it:values) tmp += string(" ") + it; values.clear(); if (fdpass_sendtof (fd,secret,"%s %s",command,tmp.c_str())==-1){ reconnect(); if (fdpass_sendtof (fd,secret,"%s %s",command,tmp.c_str())==-1){ ret = -1; } } if (ret == 0){ glocal vector *lines = &lines; (fd,10); if (strcmp(line,"Ok")==0){ end = true; }else{ glocal.lines->push_back(line); } } return ret; } int CONNECT_INFO::send (REQUEST &req) { int ret = 0; req.complete(); if (secret.size() > 0) req.sign(secret.c_str()); if (req.send(fd)==-1){ reconnect(); if (req.send(fd)==-1){ ret = -1; } } if (ret != -1) req.reset(); return ret; } int CONNECT_INFO::receive(REQUEST &req) { req.reset(); char line[10000]; int ok = 0; int len; while ((len=read(fd,line,sizeof(line)-1))>0){ line[len] = '\0'; ok = req.addpart(line); if (ok != 0) break; } return ok == 1 ? 0 : -1; } static string force_addr; void fdpass_set_force_addr (PARAM_STRING addr) { force_addr = addr.ptr; } const char *fdpass_get_force_addr() { return force_addr.c_str(); } int fdpass_sendmail ( PARAM_STRING mailserv, PARAM_STRING mailport, PARAM_STRING from, PARAM_STRING addr, // Email address PARAM_STRING subject, PARAM_STRING body) { glocal const char *from = from.ptr; glocal const char *to_addr = addr.ptr; glocal const char *body_addr = addr.ptr; glocal const char *subject = subject.ptr; glocal const char *body = body.ptr; glocal int success = 0; glocal int noline = 0; if (force_addr.size() > 0) glocal.to_addr = force_addr.c_str(); (mailserv,mailport,1); debug_printf ("sendmail: %s\n",line); if (glocal.noline==0){ sendf ("Helo writed\n"); }else if (glocal.noline == 1){ sendf ("mail from: %s\r\n",glocal.from); }else if (glocal.noline == 2){ sendf ("rcpt to: %s\r\n",glocal.to_addr); }else if (glocal.noline == 3){ sendf ("data\r\n"); }else if (glocal.noline == 4){ time_t now = time(NULL); struct tm *t = localtime(&now); int hour = t->tm_hour; const char *ampm = "AM"; if (hour > 12){ hour -= 12; ampm = "PM"; } static const char *tbday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; static const char *tbmonth[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; string date = string_f ("%s %s %d %04d %d:%02d%s",tbday[t->tm_wday],tbmonth[t->tm_mon],t->tm_mday,t->tm_year+1900 ,hour,t->tm_min,ampm); sendf ("from: no-reply@" TRUELIES "\r\n" "to: %s\r\n" "date: %s\r\n" "subject: %s\r\n" "\r\n%s\r\n.\r\n" ,glocal.body_addr ,date.c_str() ,glocal.subject ,glocal.body); }else{ glocal.success = 1; send ("quit\r\n"); end = true; } glocal.noline++; return glocal.success; }