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