1 2 #include <petscwebclient.h> 3 4 static BIO *bio_err = NULL; 5 6 #define PASSWORD "password" 7 8 #if defined(PETSC_USE_SSL_CERTIFICATE) 9 static int password_cb(char *buf,int num, int rwflag,void *userdata) 10 { 11 if (num < strlen(PASSWORD)+1) return(0); 12 strcpy(buf,PASSWORD); 13 return(strlen(PASSWORD)); 14 } 15 #endif 16 17 static void sigpipe_handle(int x) 18 { 19 } 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "PetscSSLInitializeContext" 23 /* 24 PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests. 25 26 If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with 27 28 $ saws/CA.pl -newcert (using the passphrase of password) 29 $ cat newkey.pem newcert.pem > sslclient.pem 30 31 and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 32 silly but it was all I could figure out. 33 34 */ 35 PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) 36 { 37 SSL_CTX *ctx; 38 #if defined(PETSC_USE_SSL_CERTIFICATE) 39 char keyfile[PETSC_MAX_PATH_LEN]; 40 PetscBool exists; 41 PetscErrorCode ierr; 42 #endif 43 44 PetscFunctionBegin; 45 if (!bio_err){ 46 SSL_library_init(); 47 SSL_load_error_strings(); 48 bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 49 } 50 51 /* Set up a SIGPIPE handler */ 52 signal(SIGPIPE,sigpipe_handle); 53 54 ctx = SSL_CTX_new(SSLv23_method()); 55 SSL_CTX_set_mode(ctx,SSL_MODE_AUTO_RETRY); 56 57 #if defined(PETSC_USE_SSL_CERTIFICATE) 58 /* Locate keyfile */ 59 ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 60 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 61 if (!exists) { 62 ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 63 ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 64 ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 65 ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 66 if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 67 } 68 69 /* Load our keys and certificates*/ 70 if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file"); 71 72 SSL_CTX_set_default_passwd_cb(ctx,password_cb); 73 if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file"); 74 #endif 75 76 *octx = ctx; 77 PetscFunctionReturn(0); 78 } 79 80 #undef __FUNCT__ 81 #define __FUNCT__ "PetscSSLDestroyContext" 82 PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) 83 { 84 PetscFunctionBegin; 85 SSL_CTX_free(ctx); 86 PetscFunctionReturn(0); 87 } 88 89 #undef __FUNCT__ 90 #define __FUNCT__ "PetscHTTPBuildRequest" 91 PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest) 92 { 93 char *request=0; 94 char contentlength[40],contenttype[80],*path,*host; 95 size_t request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0; 96 PetscErrorCode ierr; 97 PetscBool flg; 98 99 PetscFunctionBegin; 100 ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr); 101 ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr); 102 if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url); 103 *path = 0; 104 ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr); 105 106 ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr); 107 ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr); 108 109 if (header) { 110 ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 111 if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 112 } 113 114 ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 115 if (ctype) { 116 ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 117 ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 118 } 119 ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 120 ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 121 ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 122 ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 123 124 /* Now construct our HTTP request */ 125 request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1; 126 ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 127 ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 128 ierr = PetscStrcat(request," ");CHKERRQ(ierr); 129 ierr = PetscStrcat(request,path);CHKERRQ(ierr); 130 ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr); 131 ierr = PetscStrcat(request,host);CHKERRQ(ierr); 132 ierr = PetscFree(host);CHKERRQ(ierr); 133 ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 134 ierr = PetscStrcat(request,header);CHKERRQ(ierr); 135 if (ctype) { 136 ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 137 } 138 ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 139 ierr = PetscStrcat(request,body);CHKERRQ(ierr); 140 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 141 ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 142 143 *outrequest = request; 144 PetscFunctionReturn(0); 145 } 146 147 148 #undef __FUNCT__ 149 #define __FUNCT__ "PetscHTTPSRequest" 150 /* 151 PetscHTTPSRequest - Send a request to an HTTPS server 152 153 Input Parameters: 154 + type - either "POST" or "GET" 155 . url - URL of request host/path 156 . header - additional header information, may be NULL 157 . ctype - data type of body, for example application/json 158 . body - data to send to server 159 . ssl - obtained with PetscHTTPSConnect() 160 - buffsize - size of buffer 161 162 Output Parameter: 163 . buff - everything returned from server 164 */ 165 PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize) 166 { 167 char *request; 168 int r; 169 size_t request_len,len; 170 PetscErrorCode ierr; 171 PetscBool foundbody = PETSC_FALSE; 172 173 PetscFunctionBegin; 174 ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 175 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 176 177 r = SSL_write(ssl,request,(int)request_len); 178 switch (SSL_get_error(ssl,r)){ 179 case SSL_ERROR_NONE: 180 if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 181 break; 182 default: 183 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 184 } 185 186 /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */ 187 ierr = PetscMemzero(buff,buffsize);CHKERRQ(ierr); 188 len = 0; 189 foundbody = PETSC_FALSE; 190 do { 191 char *clen; 192 int cl; 193 size_t nlen; 194 195 r = SSL_read(ssl,buff+len,(int)buffsize); 196 len += r; 197 switch (SSL_get_error(ssl,r)){ 198 case SSL_ERROR_NONE: 199 break; 200 case SSL_ERROR_ZERO_RETURN: 201 foundbody = PETSC_TRUE; 202 SSL_shutdown(ssl); 203 break; 204 case SSL_ERROR_SYSCALL: 205 foundbody = PETSC_TRUE; 206 break; 207 default: 208 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 209 } 210 211 ierr = PetscStrstr(buff,"Content-Length: ",&clen);CHKERRQ(ierr); 212 if (clen) { 213 clen += 15; 214 sscanf(clen,"%d",&cl); 215 if (!cl) foundbody = PETSC_TRUE; 216 else { 217 ierr = PetscStrstr(buff,"\r\n\r\n",&clen);CHKERRQ(ierr); 218 if (clen) { 219 ierr = PetscStrlen(clen,&nlen);CHKERRQ(ierr); 220 if (nlen-4 == (size_t) cl) foundbody = PETSC_TRUE; 221 } 222 } 223 } else { 224 /* if no content length than must leave because you don't know if you can read again */ 225 foundbody = PETSC_TRUE; 226 } 227 } while (!foundbody); 228 ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 229 230 SSL_free(ssl); 231 ierr = PetscFree(request);CHKERRQ(ierr); 232 PetscFunctionReturn(0); 233 } 234 235 #undef __FUNCT__ 236 #define __FUNCT__ "PetscHTTPRequest" 237 /* 238 PetscHTTPRequest - Send a request to an HTTP server 239 240 Input Parameters: 241 + type - either "POST" or "GET" 242 . url - URL of request host/path 243 . header - additional header information, may be NULL 244 . ctype - data type of body, for example application/json 245 . body - data to send to server 246 . sock - obtained with PetscOpenSocket() 247 - buffsize - size of buffer 248 249 Output Parameter: 250 . buff - everything returned from server 251 */ 252 PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize) 253 { 254 char *request; 255 size_t request_len; 256 PetscErrorCode ierr; 257 258 PetscFunctionBegin; 259 ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 260 ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 261 262 ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr); 263 ierr = PetscFree(request);CHKERRQ(ierr); 264 PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR); 265 buff[buffsize-1] = 0; 266 ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr); 267 PetscFunctionReturn(0); 268 } 269 270 #undef __FUNCT__ 271 #define __FUNCT__ "PetscHTTPSConnect" 272 PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 273 { 274 BIO *sbio; 275 PetscErrorCode ierr; 276 277 PetscFunctionBegin; 278 /* Connect the TCP socket*/ 279 ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 280 281 /* Connect the SSL socket */ 282 *ssl = SSL_new(ctx); 283 sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 284 SSL_set_bio(*ssl,sbio,sbio); 285 if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 286 PetscFunctionReturn(0); 287 } 288 289 #undef __FUNCT__ 290 #define __FUNCT__ "PetscPullJSONValue" 291 /* 292 Given a JSON response containing the substring with "key" : "value" where there may or not be spaces around the : returns the value. 293 */ 294 PetscErrorCode PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool *found) 295 { 296 PetscErrorCode ierr; 297 char *v,*w; 298 char work[256]; 299 size_t len; 300 301 PetscFunctionBegin; 302 ierr = PetscStrcpy(work,"\"");CHKERRQ(ierr); 303 ierr = PetscStrncat(work,key,250);CHKERRQ(ierr); 304 ierr = PetscStrcat(work,"\":");CHKERRQ(ierr); 305 ierr = PetscStrstr(buff,work,&v);CHKERRQ(ierr); 306 ierr = PetscStrlen(work,&len);CHKERRQ(ierr); 307 if (v) { 308 v += len; 309 } else { 310 work[len++-1] = 0; 311 ierr = PetscStrcat(work," :");CHKERRQ(ierr); 312 ierr = PetscStrstr(buff,work,&v);CHKERRQ(ierr); 313 if (!v) { 314 *found = PETSC_FALSE; 315 PetscFunctionReturn(0); 316 } 317 v += len; 318 } 319 ierr = PetscStrchr(v,'\"',&v);CHKERRQ(ierr); 320 if (!v) { 321 *found = PETSC_FALSE; 322 PetscFunctionReturn(0); 323 } 324 ierr = PetscStrchr(v+1,'\"',&w);CHKERRQ(ierr); 325 if (!w) { 326 *found = PETSC_FALSE; 327 PetscFunctionReturn(0); 328 } 329 *found = PETSC_TRUE; 330 ierr = PetscStrncpy(value,v+1,PetscMin((size_t)(w-v),valuelen));CHKERRQ(ierr); 331 PetscFunctionReturn(0); 332 } 333 334 #include <ctype.h> 335 336 #undef __FUNCT__ 337 #define __FUNCT__ "PetscPushJSONValue" 338 /* 339 Pushs a "key" : "value" pair onto a string 340 341 Ignores lengths so can cause buffer overflow 342 */ 343 PetscErrorCode PetscPushJSONValue(char buff[],const char key[],const char value[],size_t bufflen) 344 { 345 PetscErrorCode ierr; 346 size_t len; 347 PetscBool special; 348 349 PetscFunctionBegin; 350 ierr = PetscStrcmp(value,"null",&special);CHKERRQ(ierr); 351 if (!special) { 352 ierr = PetscStrcmp(value,"true",&special);CHKERRQ(ierr); 353 } 354 if (!special) { 355 ierr = PetscStrcmp(value,"false",&special);CHKERRQ(ierr); 356 } 357 if (!special) { 358 PetscInt i; 359 360 ierr = PetscStrlen(value,&len);CHKERRQ(ierr); 361 special = PETSC_TRUE; 362 for (i=0; i<(int)len; i++) { 363 if (!isdigit(value[i])) { 364 special = PETSC_FALSE; 365 break; 366 } 367 } 368 } 369 370 ierr = PetscStrcat(buff,"\"");CHKERRQ(ierr); 371 ierr = PetscStrcat(buff,key);CHKERRQ(ierr); 372 ierr = PetscStrcat(buff,"\":");CHKERRQ(ierr); 373 if (!special) { 374 ierr = PetscStrcat(buff,"\"");CHKERRQ(ierr); 375 } 376 ierr = PetscStrcat(buff,value);CHKERRQ(ierr); 377 if (!special) { 378 ierr = PetscStrcat(buff,"\"");CHKERRQ(ierr); 379 } 380 PetscFunctionReturn(0); 381 } 382