1 #include "server.h" 2 #include "stat_cache.h" 3 #include "keyvalue.h" 4 #include "log.h" 5 #include "connections.h" 6 #include "joblist.h" 7 #include "http_chunk.h" 8 9 #include "plugin.h" 10 11 #include <sys/types.h> 12 13 #ifdef __WIN32 14 # include <winsock2.h> 15 #else 16 # include <sys/socket.h> 17 # include <sys/wait.h> 18 # include <sys/mman.h> 19 # include <netinet/in.h> 20 # include <arpa/inet.h> 21 #endif 22 23 #include <unistd.h> 24 #include <errno.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <fdevent.h> 28 #include <signal.h> 29 #include <ctype.h> 30 #include <assert.h> 31 32 #include <stdio.h> 33 #include <fcntl.h> 34 35 #ifdef HAVE_SYS_FILIO_H 36 # include <sys/filio.h> 37 #endif 38 39 #include "version.h" 40 41 enum {EOL_UNSET, EOL_N, EOL_RN}; 42 43 typedef struct { 44 char **ptr; 45 46 size_t size; 47 size_t used; 48 } char_array; 49 50 typedef struct { 51 pid_t *ptr; 52 size_t used; 53 size_t size; 54 } buffer_pid_t; 55 56 typedef struct { 57 array *cgi; 58 unsigned short execute_x_only; 59 } plugin_config; 60 61 typedef struct { 62 PLUGIN_DATA; 63 buffer_pid_t cgi_pid; 64 65 buffer *tmp_buf; 66 buffer *parse_response; 67 68 plugin_config **config_storage; 69 70 plugin_config conf; 71 } plugin_data; 72 73 typedef struct { 74 pid_t pid; 75 int fd; 76 int fde_ndx; /* index into the fd-event buffer */ 77 78 connection *remote_conn; /* dumb pointer */ 79 plugin_data *plugin_data; /* dumb pointer */ 80 81 buffer *response; 82 buffer *response_header; 83 } handler_ctx; 84 85 static handler_ctx * cgi_handler_ctx_init() { 86 handler_ctx *hctx = calloc(1, sizeof(*hctx)); 87 88 assert(hctx); 89 90 hctx->response = buffer_init(); 91 hctx->response_header = buffer_init(); 92 93 return hctx; 94 } 95 96 static void cgi_handler_ctx_free(handler_ctx *hctx) { 97 buffer_free(hctx->response); 98 buffer_free(hctx->response_header); 99 100 free(hctx); 101 } 102 103 enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR}; 104 105 INIT_FUNC(mod_cgi_init) { 106 plugin_data *p; 107 108 p = calloc(1, sizeof(*p)); 109 110 assert(p); 111 112 p->tmp_buf = buffer_init(); 113 p->parse_response = buffer_init(); 114 115 return p; 116 } 117 118 119 FREE_FUNC(mod_cgi_free) { 120 plugin_data *p = p_d; 121 buffer_pid_t *r = &(p->cgi_pid); 122 123 UNUSED(srv); 124 125 if (p->config_storage) { 126 size_t i; 127 for (i = 0; i < srv->config_context->used; i++) { 128 plugin_config *s = p->config_storage[i]; 129 130 array_free(s->cgi); 131 132 free(s); 133 } 134 free(p->config_storage); 135 } 136 137 138 if (r->ptr) free(r->ptr); 139 140 buffer_free(p->tmp_buf); 141 buffer_free(p->parse_response); 142 143 free(p); 144 145 return HANDLER_GO_ON; 146 } 147 148 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { 149 plugin_data *p = p_d; 150 size_t i = 0; 151 152 config_values_t cv[] = { 153 { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ 154 { "cgi.execute-x-only", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ 155 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET} 156 }; 157 158 if (!p) return HANDLER_ERROR; 159 160 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); 161 162 for (i = 0; i < srv->config_context->used; i++) { 163 plugin_config *s; 164 165 s = calloc(1, sizeof(plugin_config)); 166 assert(s); 167 168 s->cgi = array_init(); 169 s->execute_x_only = 0; 170 171 cv[0].destination = s->cgi; 172 cv[1].destination = &(s->execute_x_only); 173 174 p->config_storage[i] = s; 175 176 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { 177 return HANDLER_ERROR; 178 } 179 } 180 181 return HANDLER_GO_ON; 182 } 183 184 185 static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) { 186 int m = -1; 187 size_t i; 188 buffer_pid_t *r = &(p->cgi_pid); 189 190 UNUSED(srv); 191 192 for (i = 0; i < r->used; i++) { 193 if (r->ptr[i] > m) m = r->ptr[i]; 194 } 195 196 if (r->size == 0) { 197 r->size = 16; 198 r->ptr = malloc(sizeof(*r->ptr) * r->size); 199 } else if (r->used == r->size) { 200 r->size += 16; 201 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size); 202 } 203 204 r->ptr[r->used++] = pid; 205 206 return m; 207 } 208 209 static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) { 210 size_t i; 211 buffer_pid_t *r = &(p->cgi_pid); 212 213 UNUSED(srv); 214 215 for (i = 0; i < r->used; i++) { 216 if (r->ptr[i] == pid) break; 217 } 218 219 if (i != r->used) { 220 /* found */ 221 222 if (i != r->used - 1) { 223 r->ptr[i] = r->ptr[r->used - 1]; 224 } 225 r->used--; 226 } 227 228 return 0; 229 } 230 231 static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) { 232 char *ns; 233 const char *s; 234 int line = 0; 235 236 UNUSED(srv); 237 238 buffer_copy_string_buffer(p->parse_response, in); 239 240 for (s = p->parse_response->ptr; 241 NULL != (ns = strchr(s, '\n')); 242 s = ns + 1, line++) { 243 const char *key, *value; 244 int key_len; 245 data_string *ds; 246 247 /* strip the \n */ 248 ns[0] = '\0'; 249 250 if (ns > s && ns[-1] == '\r') ns[-1] = '\0'; 251 252 if (line == 0 && 253 0 == strncmp(s, "HTTP/1.", 7)) { 254 /* non-parsed header ... we parse them anyway */ 255 256 if ((s[7] == '1' || 257 s[7] == '0') && 258 s[8] == ' ') { 259 int status; 260 /* after the space should be a status code for us */ 261 262 status = strtol(s+9, NULL, 10); 263 264 if (status >= 100 && 265 status < 1000) { 266 /* we expected 3 digits and didn't got them */ 267 con->parsed_response |= HTTP_STATUS; 268 con->http_status = status; 269 } 270 } 271 } else { 272 /* parse the headers */ 273 key = s; 274 if (NULL == (value = strchr(s, ':'))) { 275 /* we expect: "<key>: <value>\r\n" */ 276 continue; 277 } 278 279 key_len = value - key; 280 value += 1; 281 282 /* skip LWS */ 283 while (*value == ' ' || *value == '\t') value++; 284 285 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { 286 ds = data_response_init(); 287 } 288 buffer_copy_string_len(ds->key, key, key_len); 289 buffer_copy_string(ds->value, value); 290 291 array_insert_unique(con->response.headers, (data_unset *)ds); 292 293 switch(key_len) { 294 case 4: 295 if (0 == strncasecmp(key, "Date", key_len)) { 296 con->parsed_response |= HTTP_DATE; 297 } 298 break; 299 case 6: 300 if (0 == strncasecmp(key, "Status", key_len)) { 301 con->http_status = strtol(value, NULL, 10); 302 con->parsed_response |= HTTP_STATUS; 303 } 304 break; 305 case 8: 306 if (0 == strncasecmp(key, "Location", key_len)) { 307 con->parsed_response |= HTTP_LOCATION; 308 } 309 break; 310 case 10: 311 if (0 == strncasecmp(key, "Connection", key_len)) { 312 con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0; 313 con->parsed_response |= HTTP_CONNECTION; 314 } 315 break; 316 case 14: 317 if (0 == strncasecmp(key, "Content-Length", key_len)) { 318 con->response.content_length = strtol(value, NULL, 10); 319 con->parsed_response |= HTTP_CONTENT_LENGTH; 320 } 321 break; 322 default: 323 break; 324 } 325 } 326 } 327 328 /* CGI/1.1 rev 03 - 7.2.1.2 */ 329 if ((con->parsed_response & HTTP_LOCATION) && 330 !(con->parsed_response & HTTP_STATUS)) { 331 con->http_status = 302; 332 } 333 334 return 0; 335 } 336 337 338 static int cgi_demux_response(server *srv, handler_ctx *hctx) { 339 plugin_data *p = hctx->plugin_data; 340 connection *con = hctx->remote_conn; 341 342 while(1) { 343 int n; 344 int toread; 345 346 #if defined(__WIN32) 347 buffer_prepare_copy(hctx->response, 4 * 1024); 348 #else 349 if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) { 350 buffer_prepare_copy(hctx->response, 4 * 1024); 351 } else { 352 if (toread > MAX_READ_LIMIT) toread = MAX_READ_LIMIT; 353 buffer_prepare_copy(hctx->response, toread + 1); 354 } 355 #endif 356 357 if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) { 358 if (errno == EAGAIN || errno == EINTR) { 359 /* would block, wait for signal */ 360 return FDEVENT_HANDLED_NOT_FINISHED; 361 } 362 /* error */ 363 log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd); 364 return FDEVENT_HANDLED_ERROR; 365 } 366 367 if (n == 0) { 368 /* read finished */ 369 370 con->file_finished = 1; 371 372 /* send final chunk */ 373 http_chunk_append_mem(srv, con, NULL, 0); 374 joblist_append(srv, con); 375 376 return FDEVENT_HANDLED_FINISHED; 377 } 378 379 hctx->response->ptr[n] = '\0'; 380 hctx->response->used = n+1; 381 382 /* split header from body */ 383 384 if (con->file_started == 0) { 385 int is_header = 0; 386 int is_header_end = 0; 387 size_t last_eol = 0; 388 size_t i; 389 390 buffer_append_string_buffer(hctx->response_header, hctx->response); 391 392 /** 393 * we have to handle a few cases: 394 * 395 * nph: 396 * 397 * HTTP/1.0 200 Ok\n 398 * Header: Value\n 399 * \n 400 * 401 * CGI: 402 * Header: Value\n 403 * Status: 200\n 404 * \n 405 * 406 * and different mixes of \n and \r\n combinations 407 * 408 * Some users also forget about CGI and just send a response and hope 409 * we handle it. No headers, no header-content seperator 410 * 411 */ 412 413 /* nph (non-parsed headers) */ 414 if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) is_header = 1; 415 416 for (i = 0; !is_header_end && i < hctx->response_header->used - 1; i++) { 417 char c = hctx->response_header->ptr[i]; 418 419 switch (c) { 420 case ':': 421 /* we found a colon 422 * 423 * looks like we have a normal header 424 */ 425 is_header = 1; 426 break; 427 case '\n': 428 /* EOL */ 429 if (is_header == 0) { 430 /* we got a EOL but we don't seem to got a HTTP header */ 431 432 is_header_end = 1; 433 434 break; 435 } 436 437 /** 438 * check if we saw a \n(\r)?\n sequence 439 */ 440 if (last_eol > 0 && 441 ((i - last_eol == 1) || 442 (i - last_eol == 2 && hctx->response_header->ptr[i - 1] == '\r'))) { 443 is_header_end = 1; 444 break; 445 } 446 447 last_eol = i; 448 449 break; 450 } 451 } 452 453 if (is_header_end) { 454 if (!is_header) { 455 /* no header, but a body */ 456 457 if (con->request.http_version == HTTP_VERSION_1_1) { 458 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; 459 } 460 461 http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used); 462 joblist_append(srv, con); 463 } else { 464 const char *bstart; 465 size_t blen; 466 467 /** 468 * i still points to the char after the terminating EOL EOL 469 * 470 * put it on the last \n again 471 */ 472 i--; 473 474 /* the body starts after the EOL */ 475 bstart = hctx->response_header->ptr + (i + 1); 476 blen = (hctx->response_header->used - 1) - (i + 1); 477 478 /* string the last \r?\n */ 479 if (i > 0 && (hctx->response_header->ptr[i - 1] == '\r')) { 480 i--; 481 } 482 483 hctx->response_header->ptr[i] = '\0'; 484 hctx->response_header->used = i + 1; /* the string + \0 */ 485 486 /* parse the response header */ 487 cgi_response_parse(srv, con, p, hctx->response_header); 488 489 /* enable chunked-transfer-encoding */ 490 if (con->request.http_version == HTTP_VERSION_1_1 && 491 !(con->parsed_response & HTTP_CONTENT_LENGTH)) { 492 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; 493 } 494 495 if (blen > 0) { 496 http_chunk_append_mem(srv, con, bstart, blen + 1); 497 joblist_append(srv, con); 498 } 499 } 500 501 con->file_started = 1; 502 } 503 } else { 504 http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used); 505 joblist_append(srv, con); 506 } 507 508 #if 0 509 log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr); 510 #endif 511 } 512 513 return FDEVENT_HANDLED_NOT_FINISHED; 514 } 515 516 static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { 517 int status; 518 pid_t pid; 519 plugin_data *p; 520 connection *con; 521 522 if (NULL == hctx) return HANDLER_GO_ON; 523 524 p = hctx->plugin_data; 525 con = hctx->remote_conn; 526 527 if (con->mode != p->id) return HANDLER_GO_ON; 528 529 #ifndef __WIN32 530 531 /* the connection to the browser went away, but we still have a connection 532 * to the CGI script 533 * 534 * close cgi-connection 535 */ 536 537 if (hctx->fd != -1) { 538 /* close connection to the cgi-script */ 539 fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); 540 fdevent_unregister(srv->ev, hctx->fd); 541 542 if (close(hctx->fd)) { 543 log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno)); 544 } 545 546 hctx->fd = -1; 547 hctx->fde_ndx = -1; 548 } 549 550 pid = hctx->pid; 551 552 con->plugin_ctx[p->id] = NULL; 553 554 /* is this a good idea ? */ 555 cgi_handler_ctx_free(hctx); 556 557 /* if waitpid hasn't been called by response.c yet, do it here */ 558 if (pid) { 559 /* check if the CGI-script is already gone */ 560 switch(waitpid(pid, &status, WNOHANG)) { 561 case 0: 562 /* not finished yet */ 563 #if 0 564 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) child isn't done yet, pid:", pid); 565 #endif 566 break; 567 case -1: 568 /* */ 569 if (errno == EINTR) break; 570 571 /* 572 * errno == ECHILD happens if _subrequest catches the process-status before 573 * we have read the response of the cgi process 574 * 575 * -> catch status 576 * -> WAIT_FOR_EVENT 577 * -> read response 578 * -> we get here with waitpid == ECHILD 579 * 580 */ 581 if (errno == ECHILD) return HANDLER_GO_ON; 582 583 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno)); 584 return HANDLER_ERROR; 585 default: 586 /* Send an error if we haven't sent any data yet */ 587 if (0 == con->file_started) { 588 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); 589 con->http_status = 500; 590 con->mode = DIRECT; 591 } else { 592 con->file_finished = 1; 593 } 594 595 if (WIFEXITED(status)) { 596 #if 0 597 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid); 598 #endif 599 return HANDLER_GO_ON; 600 } else { 601 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid); 602 return HANDLER_GO_ON; 603 } 604 } 605 606 607 kill(pid, SIGTERM); 608 609 /* cgi-script is still alive, queue the PID for removal */ 610 cgi_pid_add(srv, p, pid); 611 } 612 #endif 613 return HANDLER_GO_ON; 614 } 615 616 static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) { 617 plugin_data *p = p_d; 618 619 return cgi_connection_close(srv, con->plugin_ctx[p->id]); 620 } 621 622 623 static handler_t cgi_handle_fdevent(server *srv, void *ctx, int revents) { 624 handler_ctx *hctx = ctx; 625 connection *con = hctx->remote_conn; 626 627 joblist_append(srv, con); 628 629 if (hctx->fd == -1) { 630 log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd"); 631 632 return HANDLER_ERROR; 633 } 634 635 if (revents & FDEVENT_IN) { 636 switch (cgi_demux_response(srv, hctx)) { 637 case FDEVENT_HANDLED_NOT_FINISHED: 638 break; 639 case FDEVENT_HANDLED_FINISHED: 640 /* we are done */ 641 642 #if 0 643 log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished"); 644 #endif 645 cgi_connection_close(srv, hctx); 646 647 /* if we get a IN|HUP and have read everything don't exec the close twice */ 648 return HANDLER_FINISHED; 649 case FDEVENT_HANDLED_ERROR: 650 /* Send an error if we haven't sent any data yet */ 651 if (0 == con->file_started) { 652 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); 653 con->http_status = 500; 654 con->mode = DIRECT; 655 } else { 656 con->file_finished = 1; 657 } 658 659 log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: "); 660 break; 661 } 662 } 663 664 if (revents & FDEVENT_OUT) { 665 /* nothing to do */ 666 } 667 668 /* perhaps this issue is already handled */ 669 if (revents & FDEVENT_HUP) { 670 /* check if we still have a unfinished header package which is a body in reality */ 671 if (con->file_started == 0 && 672 hctx->response_header->used) { 673 con->file_started = 1; 674 http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used); 675 joblist_append(srv, con); 676 } 677 678 if (con->file_finished == 0) { 679 http_chunk_append_mem(srv, con, NULL, 0); 680 joblist_append(srv, con); 681 } 682 683 con->file_finished = 1; 684 685 if (chunkqueue_is_empty(con->write_queue)) { 686 /* there is nothing left to write */ 687 connection_set_state(srv, con, CON_STATE_RESPONSE_END); 688 } else { 689 /* used the write-handler to finish the request on demand */ 690 691 } 692 693 # if 0 694 log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents); 695 # endif 696 697 /* rtsigs didn't liked the close */ 698 cgi_connection_close(srv, hctx); 699 } else if (revents & FDEVENT_ERR) { 700 con->file_finished = 1; 701 702 /* kill all connections to the cgi process */ 703 cgi_connection_close(srv, hctx); 704 #if 1 705 log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR"); 706 #endif 707 return HANDLER_ERROR; 708 } 709 710 return HANDLER_FINISHED; 711 } 712 713 714 static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) { 715 char *dst; 716 717 if (!key || !val) return -1; 718 719 dst = malloc(key_len + val_len + 2); 720 memcpy(dst, key, key_len); 721 dst[key_len] = '='; 722 memcpy(dst + key_len + 1, val, val_len); 723 dst[key_len + 1 + val_len] = '\0'; 724 725 if (env->size == 0) { 726 env->size = 16; 727 env->ptr = malloc(env->size * sizeof(*env->ptr)); 728 } else if (env->size == env->used) { 729 env->size += 16; 730 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); 731 } 732 733 env->ptr[env->used++] = dst; 734 735 return 0; 736 } 737 738 static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) { 739 pid_t pid; 740 741 #ifdef HAVE_IPV6 742 char b2[INET6_ADDRSTRLEN + 1]; 743 #endif 744 745 int to_cgi_fds[2]; 746 int from_cgi_fds[2]; 747 struct stat st; 748 749 #ifndef __WIN32 750 751 if (cgi_handler->used > 1) { 752 /* stat the exec file */ 753 if (-1 == (stat(cgi_handler->ptr, &st))) { 754 log_error_write(srv, __FILE__, __LINE__, "sbss", 755 "stat for cgi-handler", cgi_handler, 756 "failed:", strerror(errno)); 757 return -1; 758 } 759 } 760 761 if (pipe(to_cgi_fds)) { 762 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno)); 763 return -1; 764 } 765 766 if (pipe(from_cgi_fds)) { 767 close(to_cgi_fds[0]); 768 close(to_cgi_fds[1]); 769 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno)); 770 return -1; 771 } 772 773 /* fork, execve */ 774 switch (pid = fork()) { 775 case 0: { 776 /* child */ 777 char **args; 778 int argc; 779 int i = 0; 780 char buf[32]; 781 size_t n; 782 char_array env; 783 char *c; 784 const char *s; 785 server_socket *srv_sock = con->srv_socket; 786 787 /* move stdout to from_cgi_fd[1] */ 788 close(STDOUT_FILENO); 789 dup2(from_cgi_fds[1], STDOUT_FILENO); 790 close(from_cgi_fds[1]); 791 /* not needed */ 792 close(from_cgi_fds[0]); 793 794 /* move the stdin to to_cgi_fd[0] */ 795 close(STDIN_FILENO); 796 dup2(to_cgi_fds[0], STDIN_FILENO); 797 close(to_cgi_fds[0]); 798 /* not needed */ 799 close(to_cgi_fds[1]); 800 801 /* create environment */ 802 env.ptr = NULL; 803 env.size = 0; 804 env.used = 0; 805 806 if (buffer_is_empty(con->conf.server_tag)) { 807 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_DESC)); 808 } else { 809 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_BUF_LEN(con->conf.server_tag)); 810 } 811 812 if (!buffer_is_empty(con->server_name)) { 813 size_t len = con->server_name->used - 1; 814 char *colon = strchr(con->server_name->ptr, ':'); 815 if (colon) len = colon - con->server_name->ptr; 816 817 cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), con->server_name->ptr, len); 818 } else { 819 #ifdef HAVE_IPV6 820 s = inet_ntop(srv_sock->addr.plain.sa_family, 821 srv_sock->addr.plain.sa_family == AF_INET6 ? 822 (const void *) &(srv_sock->addr.ipv6.sin6_addr) : 823 (const void *) &(srv_sock->addr.ipv4.sin_addr), 824 b2, sizeof(b2)-1); 825 #else 826 s = inet_ntoa(srv_sock->addr.ipv4.sin_addr); 827 #endif 828 cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s)); 829 } 830 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")); 831 832 s = get_http_version_name(con->request.http_version); 833 834 cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)); 835 836 LI_ltostr(buf, 837 #ifdef HAVE_IPV6 838 ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port) 839 #else 840 ntohs(srv_sock->addr.ipv4.sin_port) 841 #endif 842 ); 843 cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf)); 844 845 switch (srv_sock->addr.plain.sa_family) { 846 #ifdef HAVE_IPV6 847 case AF_INET6: 848 s = inet_ntop(srv_sock->addr.plain.sa_family, 849 (const void *) &(srv_sock->addr.ipv6.sin6_addr), 850 b2, sizeof(b2)-1); 851 break; 852 case AF_INET: 853 s = inet_ntop(srv_sock->addr.plain.sa_family, 854 (const void *) &(srv_sock->addr.ipv4.sin_addr), 855 b2, sizeof(b2)-1); 856 break; 857 #else 858 case AF_INET: 859 s = inet_ntoa(srv_sock->addr.ipv4.sin_addr); 860 break; 861 #endif 862 default: 863 s = ""; 864 break; 865 } 866 cgi_env_add(&env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)); 867 868 s = get_http_method_name(con->request.http_method); 869 cgi_env_add(&env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)); 870 871 if (!buffer_is_empty(con->request.pathinfo)) { 872 cgi_env_add(&env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); 873 } 874 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); 875 if (!buffer_is_empty(con->uri.query)) { 876 cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query)); 877 } 878 if (!buffer_is_empty(con->request.orig_uri)) { 879 cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); 880 } 881 882 883 switch (con->dst_addr.plain.sa_family) { 884 #ifdef HAVE_IPV6 885 case AF_INET6: 886 s = inet_ntop(con->dst_addr.plain.sa_family, 887 (const void *) &(con->dst_addr.ipv6.sin6_addr), 888 b2, sizeof(b2)-1); 889 break; 890 case AF_INET: 891 s = inet_ntop(con->dst_addr.plain.sa_family, 892 (const void *) &(con->dst_addr.ipv4.sin_addr), 893 b2, sizeof(b2)-1); 894 break; 895 #else 896 case AF_INET: 897 s = inet_ntoa(con->dst_addr.ipv4.sin_addr); 898 break; 899 #endif 900 default: 901 s = ""; 902 break; 903 } 904 cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s)); 905 906 LI_ltostr(buf, 907 #ifdef HAVE_IPV6 908 ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port) 909 #else 910 ntohs(con->dst_addr.ipv4.sin_port) 911 #endif 912 ); 913 cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf)); 914 915 if (!buffer_is_empty(con->authed_user)) { 916 cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"), 917 CONST_BUF_LEN(con->authed_user)); 918 } 919 920 #ifdef USE_OPENSSL 921 if (srv_sock->is_ssl) { 922 cgi_env_add(&env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")); 923 } 924 #endif 925 926 /* request.content_length < SSIZE_MAX, see request.c */ 927 LI_ltostr(buf, con->request.content_length); 928 cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)); 929 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path)); 930 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); 931 cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.basedir)); 932 933 /* for valgrind */ 934 if (NULL != (s = getenv("LD_PRELOAD"))) { 935 cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s)); 936 } 937 938 if (NULL != (s = getenv("LD_LIBRARY_PATH"))) { 939 cgi_env_add(&env, CONST_STR_LEN("LD_LIBRARY_PATH"), s, strlen(s)); 940 } 941 #ifdef __CYGWIN__ 942 /* CYGWIN needs SYSTEMROOT */ 943 if (NULL != (s = getenv("SYSTEMROOT"))) { 944 cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s)); 945 } 946 #endif 947 948 for (n = 0; n < con->request.headers->used; n++) { 949 data_string *ds; 950 951 ds = (data_string *)con->request.headers->data[n]; 952 953 if (ds->value->used && ds->key->used) { 954 size_t j; 955 956 buffer_reset(p->tmp_buf); 957 958 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) { 959 buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("HTTP_")); 960 p->tmp_buf->used--; /* strip \0 after HTTP_ */ 961 } 962 963 buffer_prepare_append(p->tmp_buf, ds->key->used + 2); 964 965 for (j = 0; j < ds->key->used - 1; j++) { 966 char cr = '_'; 967 if (light_isalpha(ds->key->ptr[j])) { 968 /* upper-case */ 969 cr = ds->key->ptr[j] & ~32; 970 } else if (light_isdigit(ds->key->ptr[j])) { 971 /* copy */ 972 cr = ds->key->ptr[j]; 973 } 974 p->tmp_buf->ptr[p->tmp_buf->used++] = cr; 975 } 976 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0'; 977 978 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value)); 979 } 980 } 981 982 for (n = 0; n < con->environment->used; n++) { 983 data_string *ds; 984 985 ds = (data_string *)con->environment->data[n]; 986 987 if (ds->value->used && ds->key->used) { 988 size_t j; 989 990 buffer_reset(p->tmp_buf); 991 992 buffer_prepare_append(p->tmp_buf, ds->key->used + 2); 993 994 for (j = 0; j < ds->key->used - 1; j++) { 995 char cr = '_'; 996 if (light_isalpha(ds->key->ptr[j])) { 997 /* upper-case */ 998 cr = ds->key->ptr[j] & ~32; 999 } else if (light_isdigit(ds->key->ptr[j])) { 1000 /* copy */ 1001 cr = ds->key->ptr[j]; 1002 } 1003 p->tmp_buf->ptr[p->tmp_buf->used++] = cr; 1004 } 1005 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0'; 1006 1007 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value)); 1008 } 1009 } 1010 1011 if (env.size == env.used) { 1012 env.size += 16; 1013 env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr)); 1014 } 1015 1016 env.ptr[env.used] = NULL; 1017 1018 /* set up args */ 1019 argc = 3; 1020 args = malloc(sizeof(*args) * argc); 1021 i = 0; 1022 1023 if (cgi_handler->used > 1) { 1024 args[i++] = cgi_handler->ptr; 1025 } 1026 args[i++] = con->physical.path->ptr; 1027 args[i ] = NULL; 1028 1029 /* search for the last / */ 1030 if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) { 1031 *c = '\0'; 1032 1033 /* change to the physical directory */ 1034 if (-1 == chdir(con->physical.path->ptr)) { 1035 log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path); 1036 } 1037 *c = '/'; 1038 } 1039 1040 /* we don't need the client socket */ 1041 for (i = 3; i < 256; i++) { 1042 if (i != srv->errorlog_fd) close(i); 1043 } 1044 1045 /* exec the cgi */ 1046 execve(args[0], args, env.ptr); 1047 1048 /* log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]); */ 1049 1050 /* */ 1051 SEGFAULT(); 1052 break; 1053 } 1054 case -1: 1055 /* error */ 1056 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno)); 1057 close(from_cgi_fds[0]); 1058 close(from_cgi_fds[1]); 1059 close(to_cgi_fds[0]); 1060 close(to_cgi_fds[1]); 1061 return -1; 1062 break; 1063 default: { 1064 handler_ctx *hctx; 1065 /* father */ 1066 1067 close(from_cgi_fds[1]); 1068 close(to_cgi_fds[0]); 1069 1070 if (con->request.content_length) { 1071 chunkqueue *cq = con->request_content_queue; 1072 chunk *c; 1073 1074 assert(chunkqueue_length(cq) == (off_t)con->request.content_length); 1075 1076 /* there is content to send */ 1077 for (c = cq->first; c; c = cq->first) { 1078 int r = 0; 1079 1080 /* copy all chunks */ 1081 switch(c->type) { 1082 case FILE_CHUNK: 1083 1084 if (c->file.mmap.start == MAP_FAILED) { 1085 if (-1 == c->file.fd && /* open the file if not already open */ 1086 -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { 1087 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); 1088 1089 close(from_cgi_fds[0]); 1090 close(to_cgi_fds[1]); 1091 return -1; 1092 } 1093 1094 c->file.mmap.length = c->file.length; 1095 1096 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) { 1097 log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", 1098 strerror(errno), c->file.name, c->file.fd); 1099 1100 close(from_cgi_fds[0]); 1101 close(to_cgi_fds[1]); 1102 return -1; 1103 } 1104 1105 close(c->file.fd); 1106 c->file.fd = -1; 1107 1108 /* chunk_reset() or chunk_free() will cleanup for us */ 1109 } 1110 1111 if ((r = write(to_cgi_fds[1], c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) { 1112 switch(errno) { 1113 case ENOSPC: 1114 con->http_status = 507; 1115 break; 1116 case EINTR: 1117 continue; 1118 default: 1119 con->http_status = 403; 1120 break; 1121 } 1122 } 1123 break; 1124 case MEM_CHUNK: 1125 if ((r = write(to_cgi_fds[1], c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) { 1126 switch(errno) { 1127 case ENOSPC: 1128 con->http_status = 507; 1129 break; 1130 case EINTR: 1131 continue; 1132 default: 1133 con->http_status = 403; 1134 break; 1135 } 1136 } 1137 break; 1138 case UNUSED_CHUNK: 1139 break; 1140 } 1141 1142 if (r > 0) { 1143 c->offset += r; 1144 cq->bytes_out += r; 1145 } else { 1146 log_error_write(srv, __FILE__, __LINE__, "ss", "write() failed due to: ", strerror(errno)); 1147 con->http_status = 500; 1148 break; 1149 } 1150 chunkqueue_remove_finished_chunks(cq); 1151 } 1152 } 1153 1154 close(to_cgi_fds[1]); 1155 1156 /* register PID and wait for them asyncronously */ 1157 con->mode = p->id; 1158 buffer_reset(con->physical.path); 1159 1160 hctx = cgi_handler_ctx_init(); 1161 1162 hctx->remote_conn = con; 1163 hctx->plugin_data = p; 1164 hctx->pid = pid; 1165 hctx->fd = from_cgi_fds[0]; 1166 hctx->fde_ndx = -1; 1167 1168 con->plugin_ctx[p->id] = hctx; 1169 1170 fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx); 1171 fdevent_event_set(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); 1172 1173 if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) { 1174 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); 1175 1176 fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); 1177 fdevent_unregister(srv->ev, hctx->fd); 1178 1179 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd); 1180 1181 close(hctx->fd); 1182 1183 cgi_handler_ctx_free(hctx); 1184 1185 con->plugin_ctx[p->id] = NULL; 1186 1187 return -1; 1188 } 1189 1190 break; 1191 } 1192 } 1193 1194 return 0; 1195 #else 1196 return -1; 1197 #endif 1198 } 1199 1200 #define PATCH(x) \ 1201 p->conf.x = s->x; 1202 static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) { 1203 size_t i, j; 1204 plugin_config *s = p->config_storage[0]; 1205 1206 PATCH(cgi); 1207 PATCH(execute_x_only); 1208 1209 /* skip the first, the global context */ 1210 for (i = 1; i < srv->config_context->used; i++) { 1211 data_config *dc = (data_config *)srv->config_context->data[i]; 1212 s = p->config_storage[i]; 1213 1214 /* condition didn't match */ 1215 if (!config_check_cond(srv, con, dc)) continue; 1216 1217 /* merge config */ 1218 for (j = 0; j < dc->value->used; j++) { 1219 data_unset *du = dc->value->data[j]; 1220 1221 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) { 1222 PATCH(cgi); 1223 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.execute-x-only"))) { 1224 PATCH(execute_x_only); 1225 } 1226 } 1227 } 1228 1229 return 0; 1230 } 1231 #undef PATCH 1232 1233 URIHANDLER_FUNC(cgi_is_handled) { 1234 size_t k, s_len; 1235 plugin_data *p = p_d; 1236 buffer *fn = con->physical.path; 1237 stat_cache_entry *sce = NULL; 1238 1239 if (con->mode != DIRECT) return HANDLER_GO_ON; 1240 1241 if (fn->used == 0) return HANDLER_GO_ON; 1242 1243 mod_cgi_patch_connection(srv, con, p); 1244 1245 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) return HANDLER_GO_ON; 1246 if (!S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON; 1247 if (p->conf.execute_x_only == 1 && (sce->st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON; 1248 1249 s_len = fn->used - 1; 1250 1251 for (k = 0; k < p->conf.cgi->used; k++) { 1252 data_string *ds = (data_string *)p->conf.cgi->data[k]; 1253 size_t ct_len = ds->key->used - 1; 1254 1255 if (ds->key->used == 0) continue; 1256 if (s_len < ct_len) continue; 1257 1258 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) { 1259 if (cgi_create_env(srv, con, p, ds->value)) { 1260 con->mode = DIRECT; 1261 con->http_status = 500; 1262 1263 buffer_reset(con->physical.path); 1264 return HANDLER_FINISHED; 1265 } 1266 /* one handler is enough for the request */ 1267 break; 1268 } 1269 } 1270 1271 return HANDLER_GO_ON; 1272 } 1273 1274 TRIGGER_FUNC(cgi_trigger) { 1275 plugin_data *p = p_d; 1276 size_t ndx; 1277 /* the trigger handle only cares about lonely PID which we have to wait for */ 1278 #ifndef __WIN32 1279 1280 for (ndx = 0; ndx < p->cgi_pid.used; ndx++) { 1281 int status; 1282 1283 switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) { 1284 case 0: 1285 /* not finished yet */ 1286 #if 0 1287 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) child isn't done yet, pid:", p->cgi_pid.ptr[ndx]); 1288 #endif 1289 break; 1290 case -1: 1291 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno)); 1292 1293 return HANDLER_ERROR; 1294 default: 1295 1296 if (WIFEXITED(status)) { 1297 #if 0 1298 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", p->cgi_pid.ptr[ndx]); 1299 #endif 1300 } else if (WIFSIGNALED(status)) { 1301 /* FIXME: what if we killed the CGI script with a kill(..., SIGTERM) ? 1302 */ 1303 if (WTERMSIG(status) != SIGTERM) { 1304 log_error_write(srv, __FILE__, __LINE__, "sd", "cleaning up CGI: process died with signal", WTERMSIG(status)); 1305 } 1306 } else { 1307 log_error_write(srv, __FILE__, __LINE__, "s", "cleaning up CGI: ended unexpectedly"); 1308 } 1309 1310 cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]); 1311 /* del modified the buffer structure 1312 * and copies the last entry to the current one 1313 * -> recheck the current index 1314 */ 1315 ndx--; 1316 } 1317 } 1318 #endif 1319 return HANDLER_GO_ON; 1320 } 1321 1322 /* 1323 * - HANDLER_GO_ON : not our job 1324 * - HANDLER_FINISHED: got response header 1325 * - HANDLER_WAIT_FOR_EVENT: waiting for response header 1326 */ 1327 SUBREQUEST_FUNC(mod_cgi_handle_subrequest) { 1328 int status; 1329 plugin_data *p = p_d; 1330 handler_ctx *hctx = con->plugin_ctx[p->id]; 1331 1332 if (con->mode != p->id) return HANDLER_GO_ON; 1333 if (NULL == hctx) return HANDLER_GO_ON; 1334 1335 #if 0 1336 log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid); 1337 #endif 1338 1339 if (hctx->pid == 0) { 1340 /* cgi already dead */ 1341 if (!con->file_started) return HANDLER_WAIT_FOR_EVENT; 1342 return HANDLER_FINISHED; 1343 } 1344 1345 #ifndef __WIN32 1346 switch(waitpid(hctx->pid, &status, WNOHANG)) { 1347 case 0: 1348 /* we only have for events here if we don't have the header yet, 1349 * otherwise the event-handler will send us the incoming data */ 1350 if (con->file_started) return HANDLER_FINISHED; 1351 1352 return HANDLER_WAIT_FOR_EVENT; 1353 case -1: 1354 if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT; 1355 1356 if (errno == ECHILD && con->file_started == 0) { 1357 /* 1358 * second round but still not response 1359 */ 1360 return HANDLER_WAIT_FOR_EVENT; 1361 } 1362 1363 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno)); 1364 con->mode = DIRECT; 1365 con->http_status = 500; 1366 1367 hctx->pid = 0; 1368 1369 fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); 1370 fdevent_unregister(srv->ev, hctx->fd); 1371 1372 if (close(hctx->fd)) { 1373 log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno)); 1374 } 1375 1376 cgi_handler_ctx_free(hctx); 1377 1378 con->plugin_ctx[p->id] = NULL; 1379 1380 return HANDLER_FINISHED; 1381 default: 1382 /* cgi process exited 1383 */ 1384 1385 hctx->pid = 0; 1386 1387 /* we already have response headers? just continue */ 1388 if (con->file_started) return HANDLER_FINISHED; 1389 1390 if (WIFEXITED(status)) { 1391 /* clean exit - just continue */ 1392 return HANDLER_WAIT_FOR_EVENT; 1393 } 1394 1395 /* cgi proc died, and we didn't get any data yet - send error message and close cgi con */ 1396 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?"); 1397 1398 con->http_status = 500; 1399 con->mode = DIRECT; 1400 1401 fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); 1402 fdevent_unregister(srv->ev, hctx->fd); 1403 1404 if (close(hctx->fd)) { 1405 log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno)); 1406 } 1407 1408 cgi_handler_ctx_free(hctx); 1409 1410 con->plugin_ctx[p->id] = NULL; 1411 return HANDLER_FINISHED; 1412 } 1413 #else 1414 return HANDLER_ERROR; 1415 #endif 1416 } 1417 1418 1419 int mod_cgi_plugin_init(plugin *p); 1420 int mod_cgi_plugin_init(plugin *p) { 1421 p->version = LIGHTTPD_VERSION_ID; 1422 p->name = buffer_init_string("cgi"); 1423 1424 p->connection_reset = cgi_connection_close_callback; 1425 p->handle_subrequest_start = cgi_is_handled; 1426 p->handle_subrequest = mod_cgi_handle_subrequest; 1427 #if 0 1428 p->handle_fdevent = cgi_handle_fdevent; 1429 #endif 1430 p->handle_trigger = cgi_trigger; 1431 p->init = mod_cgi_init; 1432 p->cleanup = mod_cgi_free; 1433 p->set_defaults = mod_fastcgi_set_defaults; 1434 1435 p->data = NULL; 1436 1437 return 0; 1438 } 1439