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