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