/******************* Grab an ordinary authenticated message off this socket. The format is: -4 byte client ID number (returned by createSalt earlier) -4 byte client challenge (used to by client to authenticate reply) -20 byte authentication hash code -Regular CcsMessageHeader */ static const char *CcsServer_SHA1_message(SOCKET fd,CCS_AUTH_clients *cl, CcsSecMan *security,CcsSecAttr *attr, CcsMessageHeader *hdr) { ChMessageInt_t clientNo_net; int clientNo; unsigned int salt; SHA1_hash_t hash; /* An ordinary authenticated message */ if (-1==skt_recvN(fd,&clientNo_net,sizeof(clientNo_net))) return "ERROR> During recv. client number"; if (-1==skt_recvN(fd,&attr->replySalt,sizeof(attr->replySalt))) return "ERROR> During recv. reply salt"; if (-1==skt_recvN(fd,&hash,sizeof(hash))) return "ERROR> During recv. authentication hash"; if (-1==skt_recvN(fd,hdr,sizeof(CcsMessageHeader))) return "ERROR> During recv. message header"; clientNo=ChMessageInt(clientNo_net); if (clientNo<0 || clientNo>=CCS_AUTH_numClients(cl)) return "ERROR> Bad client number in SHA-1 request!"; salt=CCS_AUTH_clientSalt(cl,clientNo); /*Check the client's hash*/ if (CCS_AUTH_differ(security->getKey(security,attr),salt, hdr,&hash)) return "ERROR> Authentication hash code MISMATCH-- bad or faked key"; CCS_AUTH_advanceSalt(cl,clientNo); return NULL; /*It's a good message*/ }
/******************************************************** Authenticate incoming request for a client salt value. Exchange looks like: 1.) Client sends request code 0x80 (SHA-1), 0x00 (version 0), 0x01 (create salt), 0xNN (security level); followed by client challenge (4 bytes, s1) 2.) Server replies with server challenge (4 bytes, s2) 3.) Client replies with hashed key & server challenge (20 bytes, s2hash) 4.) Server replies with hashed key & client challenge (20 bytes, s1hash), as well as client identifier and initial client salt. (8 bytes total). */ static const char *CcsServer_createSalt(SOCKET fd,CCS_AUTH_clients *cl, CcsSecMan *security,CcsSecAttr *attr) { ChMessageInt_t s1; ChMessageInt_t s2=ChMessageInt_new(CCS_RAND_next(&cl->rand)); SHA1_hash_t s2hash; int clientId; struct { SHA1_hash_t s1hash; ChMessageInt_t clientId; ChMessageInt_t clientSalt; } reply; if (-1==skt_recvN(fd,&s1,sizeof(s1))) return "ERROR> CreateSalt challenge recv"; if (-1==skt_sendN(fd,&s2,sizeof(s2))) return "ERROR> CreateSalt challenge send"; if (-1==skt_recvN(fd,&s2hash,sizeof(s2hash))) return "ERROR> CreateSalt reply recv"; if (CCS_AUTH_differ(security->getKey(security,attr),ChMessageInt(s2), NULL,&s2hash)) return "ERROR> CreateSalt client hash mismatch! (bad password?)"; CCS_AUTH_hash(security->getKey(security,attr),ChMessageInt(s1), NULL,&reply.s1hash); clientId=CCS_AUTH_addClient(cl); reply.clientId=ChMessageInt_new(clientId); reply.clientSalt=ChMessageInt_new(CCS_AUTH_clientSalt(cl,clientId)); if (-1==skt_sendN(fd,&reply,sizeof(reply))) return "ERROR> CreateSalt reply send"; /*HACK: this isn't an error return, and returning an error code here is wrong; but all we want is to close the socket (not process a CCS request), and printing out this text isn't a bad idea, so... */ return "Created new client"; }
/********************* Grab a message header from this socket. */ static const char *CcsServer_readHeader(SOCKET fd,CCS_AUTH_clients *cl, CcsSecMan *security, CcsSecAttr *attr,CcsMessageHeader *hdr) { /*Read the first bytes*/ unsigned char len[4]; if (-1==skt_recvN(fd,&len[0],sizeof(len))) return "ERROR> During recv. length"; /* Decide what kind of message it is by the high byte of the length field. */ if (len[0]<0x20) { /*Unauthenticated message-- do a security check*/ attr->auth=0; attr->level=0; attr->replySalt=ChMessageInt_new(0); if (!security->allowRequest(security,attr)) return "ERROR> Unauthenticated request denied at security check"; /*Request is authorized-- grab the rest of the header*/ hdr->len=*(ChMessageInt_t *)len; if (-1==skt_recvN(fd,&hdr->pe,sizeof(hdr->pe))) return "ERROR> During recv. PE"; if (-1==skt_recvN(fd,&hdr->handler[0],sizeof(hdr->handler))) return "ERROR> During recv. handler name"; return NULL; /*it's a good message*/ } else if (len[0]==0x80) { /*SHA-1 Authenticated request*/ if (len[1]!=0x00) return "ERROR> Bad SHA-1 version field!"; attr->auth=1; attr->level=len[3];/*Requested security level.*/ if (!security->allowRequest(security,attr)) return "ERROR> Authenticated request denied at security check"; switch(len[2]) { case 0x00: /*Regular message*/ return CcsServer_SHA1_message(fd,cl,security,attr,hdr); case 0x01: /*Request for salt*/ return CcsServer_createSalt(fd,cl,security,attr); default: return "ERROR> Bad SHA-1 request field!"; }; } else return "ERROR> Unknown authentication protocol"; }
static char *skt_recv_line(SOCKET s) { char c; char *buf; int i=0; int currlen=256; buf = CALLOC(currlen, sizeof(char)); while (1) { skt_recvN(s,&c,1); if (c=='\r') continue; // ignore if by itself, break if \n follows if (c=='\n') { buf[i]='\0'; break; } buf[i++]=c; if (i==currlen-1) { currlen += 256; char *newbuf = CALLOC(currlen, sizeof(char)); memcpy(newbuf, buf, currlen-256); free(buf); buf = newbuf; } } return buf; }
static int CcsServer_recvRequestData(SOCKET fd, CcsImplHeader *hdr,void **reqData) { CcsMessageHeader req;/*CCS header, from requestor*/ int reqBytes, numPes, destPE; const char *err; if (NULL!=(err=CcsServer_readHeader(fd,&ccs_clientlist,security, &hdr->attr,&req))) { /*Not a regular message-- write error message and return error.*/ fprintf(stdout,"CCS %s\n",err); return 0; } /*Fill out the internal CCS header*/ strncpy(hdr->handler,req.handler,CCS_MAXHANDLER); hdr->pe=req.pe; hdr->len=req.len; hdr->replyFd=ChMessageInt_new(fd); /*Is it a multicast?*/ numPes = 0; destPE = ChMessageInt(hdr->pe); if (destPE < -1) numPes = -destPE; /*Grab the user data portion of the message*/ reqBytes=ChMessageInt(req.len) + numPes*sizeof(ChMessageInt_t); *reqData=(char *)malloc(reqBytes); if (-1==skt_recvN(fd,*reqData,reqBytes)) { fprintf(stdout,"CCS ERROR> Retrieving %d message bytes\n",reqBytes); free(*reqData); return 0; } return 1; }
int ChMessageData_recv(SOCKET fd,ChMessage *dst) { dst->data=(char *)malloc(dst->len); /*Get the actual data*/ if (0!=skt_recvN(fd,dst->data,dst->len)) return -1; return 0; }
int ChMessageHeader_recv(SOCKET fd,ChMessage *dst) { /*Get the binary header*/ if (0!=skt_recvN(fd,(char *)&dst->header,sizeof(dst->header))) return -1; /*Allocate a recieve buffer*/ dst->len=ChMessageInt(dst->header.len); dst->data=0; return 0; }
/** Receive all HTTP content as a single std::string */ std::string osl::http_connection::receive(void) { std::string lengthStr=receive_header("Content-Length"); int length=0; sscanf(lengthStr.c_str(),"%d",&length); p.status(1,"Retrieving "+int2str(length/1024)+" KiB of HTTP data from "+host); std::string data(length,0x00); enum {chunkSize=8*1024}; for (int start=0;start<length;start+=chunkSize) { int amt=my_min(data.size()-start,chunkSize); skt_recvN(s,&data[start],amt); p.status(2,"Retrieved "+int2str((start+amt)/1024)+" KiB so far from "+host); } if (length<1024) p.status(3,"Incoming data: "+data); return data; }
// Loop to handle connection and recieve messages void TCPConnection::loop(){ const char *term=" \t\r\n"; std::string message = ""; char c; onOpen(); while(!_dead){ if(skt_recvN(_socket,&c,1) != 0){ fail(); // Connection failure } else if(strchr(term,c)){ if(c=='\r') continue; // will be CR/LF; wait for LF onMessage(message); message = ""; } else{ message+=c; // normal character } } }
unsigned char *download_url(const char *url_in, int verbose, int *length) { char *url=STRDUP(url_in); // parse the url char *protocol, *host, *path; int port; parse_url(url, &protocol, &host, &port, &path); if (verbose) printf("Connecting to URL: %s://%s:%d%s\n", protocol, host, port, path); int timeout = 60; if (verbose) printf("Looking up IP Address for: %s\n", host); skt_ip_t hostIP = skt_lookup_ip(host); if (verbose) printf("Connecting to %s\n", host); SOCKET s = skt_connect(hostIP, port, timeout); char *send_get = MALLOC(strlen(url)+128); sprintf(send_get, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "User-Agent: Mozilla/5.0\r\n" "\r\n", path, host); // send our get request skt_sendN(s, send_get, strlen(send_get)); // wait... if (verbose) printf("Waiting for a response from %s\n", host); char *status = skt_recv_line(s); if (verbose) printf("Received status: %s\n", status); //char *status_trim = trim_spaces(status); free(status); // now can get the response code //int code = atoi(status_trim); //free(status_trim); // a zero-length line indicates the end of the HTTP headers... we ignore int len=-1; while (1) { char *line = skt_recv_line(s); if (strlen(line)==0) break; if (strstr(line, "Content-Length") != 0) { char *l = line + strlen("Content-Length") + 2; len=atoi(l); } } if (verbose) printf("Content Length: %d\n", len); if (len==-1) { asfPrintWarning("No Content-Length specified in the HTTP headers.\n"); return NULL; } // receiving data... unsigned char *data = CALLOC(len+12, sizeof(char)); int curr=0, chunkSize=1024; while (1) { int amt = chunkSize < len-curr ? chunkSize : len-curr; skt_recvN(s,data+curr,amt); curr += amt; if (verbose) printf("Retrieved %d Kb so far.\n", curr); if (curr==len) break; else if (curr>len) asfPrintError("Invalid Content-Length?\n"); } if(verbose) printf("Done.\n"); //if (verbose) // printf("Received data:\n" // "-------------------------------------------------------------\n" // "%s\n" // "-------------------------------------------------------------\n", // data); free(protocol); free(host); free(path); free(url); free(send_get); skt_close(s); *length = len; return data; }