Apache HTTPD
mod_authnz_fcgi.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr_hash.h"
18#include "apr_lib.h"
19#include "apr_strings.h"
20
21#include "ap_provider.h"
22#include "httpd.h"
23#include "http_config.h"
24#include "http_core.h"
25#include "http_protocol.h"
26#include "http_request.h"
27#include "http_log.h"
28#include "util_script.h"
29#include "ap_provider.h"
30#include "mod_auth.h"
31#include "util_fcgi.h"
32#include "ap_mmn.h"
33
34module AP_MODULE_DECLARE_DATA authnz_fcgi_module;
35
36typedef struct {
37 const char *name; /* provider name */
38 const char *backend; /* backend address, as configured */
39 const char *host;
45
46typedef struct {
47 const char *name; /* provider name */
48 const char *default_user; /* this is user if authorizer returns
49 * success and a user expression yields
50 * empty string
51 */
52 ap_expr_info_t *user_expr; /* expr to evaluate to set r->user */
53 char authoritative; /* fail request if user is rejected? */
54 char require_basic_auth; /* fail if client didn't send credentials? */
56
57typedef struct {
58 /* If an "authnz" provider successfully authenticates, record
59 * the provider name here for checking during authz.
60 */
63
65
66#define FCGI_IO_TIMEOUT apr_time_from_sec(30)
67
68#ifndef NON200_RESPONSE_BUF_LEN
69#define NON200_RESPONSE_BUF_LEN 8192
70#endif
71
72/* fcgi://{hostname|IPv4|IPv6}:port[/] */
73#define FCGI_BACKEND_REGEX_STR "m%^fcgi://(.*):(\\d{1,5})/?$%"
74
75/*
76 * utility function to connect to a peer; generally useful, but
77 * wait for AF_UNIX support in this mod before thinking about how
78 * to make it available to other modules
79 */
82 apr_sockaddr_t *backend_addrs,
83 const char *backend_name,
85{
86 apr_status_t rv = APR_EINVAL; /* returned if no backend addr was provided
87 */
88 int connected = 0;
89 apr_sockaddr_t *addr = backend_addrs;
90
91 while (addr && !connected) {
92 int loglevel = addr->next ? APLOG_DEBUG : APLOG_ERR;
94 SOCK_STREAM, 0, r->pool);
95 if (rv != APR_SUCCESS) {
96 ap_log_rerror(APLOG_MARK, loglevel, rv, r,
97 APLOGNO(02494) "error creating family %d socket "
98 "for target %s",
100 addr = addr->next;
101 continue;
102 }
103
107
109 if (rv != APR_SUCCESS) {
111 ap_log_rerror(APLOG_MARK, loglevel, rv, r,
112 APLOGNO(02495) "attempt to connect to %pI (%s) "
113 "failed", addr, backend_name);
114 addr = addr->next;
115 continue;
116 }
117
118 connected = 1;
119 }
120
121 return rv;
122#undef FN_LOG_MARK
123}
124
126{
128 APLOGNO(02496) "name %s, backend %s, host %s, port %d, "
129 "first address %pI, %c%c",
130 conf->name,
131 conf->backend,
132 conf->host,
133 (int)conf->port,
134 conf->backend_addrs,
135 conf->is_authn ? 'N' : '_',
136 conf->is_authz ? 'Z' : '_');
137}
138
139static void setupenv(request_rec *r, const char *password, const char *apache_role)
140{
144 if (apache_role) {
145 apr_table_setn(r->subprocess_env, "FCGI_APACHE_ROLE", apache_role);
146 }
147 if (password) {
148 apr_table_setn(r->subprocess_env, "REMOTE_PASSWD", password);
149 }
150 /* Drop the variables CONTENT_LENGTH, PATH_INFO, PATH_TRANSLATED,
151 * SCRIPT_NAME and most Hop-By-Hop headers - EXCEPT we will pass
152 * PROXY_AUTH to allow CGI to perform proxy auth for httpd
153 */
154 apr_table_unset(r->subprocess_env, "CONTENT_LENGTH");
155 apr_table_unset(r->subprocess_env, "PATH_INFO");
156 apr_table_unset(r->subprocess_env, "PATH_TRANSLATED");
157 apr_table_unset(r->subprocess_env, "SCRIPT_NAME");
158 apr_table_unset(r->subprocess_env, "HTTP_KEEP_ALIVE");
159 apr_table_unset(r->subprocess_env, "HTTP_TE");
160 apr_table_unset(r->subprocess_env, "HTTP_TRAILER");
161 apr_table_unset(r->subprocess_env, "HTTP_TRANSFER_ENCODING");
162 apr_table_unset(r->subprocess_env, "HTTP_UPGRADE");
163
164 /* Connection hop-by-hop header to prevent the CGI from hanging */
165 apr_table_setn(r->subprocess_env, "HTTP_CONNECTION", "close");
166}
167
169 request_rec *r,
171 char *buf,
173{
174 apr_status_t rv;
175
176 rv = apr_socket_recv(s, buf, buflen);
177 if (rv != APR_SUCCESS) {
179 APLOGNO(02497) "Couldn't read from backend %s",
180 conf->backend);
181 return rv;
182 }
183
184#if AP_MODULE_MAGIC_AT_LEAST(20130702,2)
185 ap_log_rdata(APLOG_MARK, APLOG_TRACE5, r, "FastCGI data received",
187#endif
188 return APR_SUCCESS;
189}
190
192 request_rec *r,
194 char *buf,
196{
199 apr_status_t rv;
200
201 do {
203 rv = recv_data(conf, r, s, buf + cumulative_len, &readlen);
204 if (rv != APR_SUCCESS) {
205 return rv;
206 }
208 } while (cumulative_len < buflen);
209
210 return APR_SUCCESS;
211}
212
214 request_rec *r,
216 struct iovec *vec,
217 int nvec,
219{
220 apr_size_t to_write = 0, written = 0;
222 int i, offset;
223
224 for (i = 0; i < nvec; i++) {
225 to_write += vec[i].iov_len;
226#if AP_MODULE_MAGIC_AT_LEAST(20130702,2)
227 ap_log_rdata(APLOG_MARK, APLOG_TRACE5, r, "FastCGI data sent",
229#endif
230 }
231
232 offset = 0;
233 while (to_write) {
234 apr_size_t n = 0;
235 rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
236 if (rv != APR_SUCCESS) {
238 APLOGNO(02498) "Sending data to %s failed",
239 conf->backend);
240 break;
241 }
242 if (n > 0) {
243 written += n;
244 if (written >= to_write)
245 break; /* short circuit out */
246 for (i = offset; i < nvec; ) {
247 if (n >= vec[i].iov_len) {
248 offset++;
249 n -= vec[i++].iov_len;
250 } else {
251 vec[i].iov_len -= n;
252 vec[i].iov_base = (char *) vec[i].iov_base + n;
253 break;
254 }
255 }
256 }
257 }
258
259 *len = written;
260
261 return rv;
262}
263
265 const fcgi_provider_conf *conf,
266 apr_socket_t *s, int role,
268{
269 struct iovec vec[2];
270 ap_fcgi_header header;
271 unsigned char farray[AP_FCGI_HEADER_LEN];
273 unsigned char abrb[AP_FCGI_HEADER_LEN];
275
277 sizeof(abrb), 0);
278 ap_fcgi_fill_in_request_body(&brb, role, 0 /* *NOT* AP_FCGI_KEEP_CONN */);
279
282
283 vec[0].iov_base = (void *)farray;
284 vec[0].iov_len = sizeof(farray);
285 vec[1].iov_base = (void *)abrb;
286 vec[1].iov_len = sizeof(abrb);
287
288 return sendv_data(conf, r, s, vec, 2, &len);
289}
290
292 const fcgi_provider_conf *conf,
295{
296 const char *fn = "send_environment";
298 const apr_table_entry_t *elts;
299 struct iovec vec[2];
300 ap_fcgi_header header;
301 unsigned char farray[AP_FCGI_HEADER_LEN];
302 char *body;
303 apr_status_t rv;
306
308 elts = (const apr_table_entry_t *) envarr->elts;
309
311
312 for (i = 0; i < envarr->nelts; ++i) {
313 if (!elts[i].key) {
314 continue;
315 }
317 "%s: '%s': '%s'",
318 fn, elts[i].key,
319 !strcmp(elts[i].key, "REMOTE_PASSWD") ?
320 "XXXXXXXX" : elts[i].val);
321 }
322 }
323
324 /* Send envvars over in as many FastCGI records as it takes, */
325 next_elem = 0; /* starting with the first one */
326
327 avail_len = 16 * 1024; /* our limit per record, which could have been up
328 * to AP_FCGI_MAX_CONTENT_LEN
329 */
330
334 avail_len,
335 &next_elem);
336
337 if (!required_len) {
340 APLOGNO(02499) "couldn't encode envvar '%s' in %"
341 APR_SIZE_T_FMT " bytes",
342 elts[next_elem].key, avail_len);
343 /* skip this envvar and continue */
344 ++next_elem;
345 continue;
346 }
347 /* only an unused element at the end of the array */
348 break;
349 }
350
352 APLOGNO(02500) "required len for encoding envvars: %"
353 APR_SIZE_T_FMT ", %d/%d elems processed so far",
354 required_len, next_elem, envarr->nelts);
355
359 /* we pre-compute, so we can't run out of space */
360 ap_assert(rv == APR_SUCCESS);
361 /* compute and encode must be in sync */
363
367
368 vec[0].iov_base = (void *)farray;
369 vec[0].iov_len = sizeof(farray);
370 vec[1].iov_base = body;
371 vec[1].iov_len = required_len;
372
373 rv = sendv_data(conf, r, s, vec, 2, &len);
375
376 if (rv) {
377 return rv;
378 }
379 }
380
381 /* Envvars sent, so say we're done */
384
385 vec[0].iov_base = (void *)farray;
386 vec[0].iov_len = sizeof(farray);
387
388 return sendv_data(conf, r, s, vec, 1, &len);
389}
390
391/*
392 * This header-state logic is from mod_proxy_fcgi.
393 */
394enum {
402
403/* Try to find the end of the script headers in the response from the back
404 * end fastcgi server. STATE holds the current header parsing state for this
405 * request.
406 *
407 * Returns 0 if it can't find the end of the headers, and 1 if it found the
408 * end of the headers. */
409static int handle_headers(request_rec *r, int *state,
410 const char *readbuf, apr_size_t readlen)
411{
412 const char *itr = readbuf;
413
414 while (readlen--) {
415 if (*itr == '\r') {
416 switch (*state) {
418 *state = HDR_STATE_GOT_CRLFCR;
419 break;
420
421 default:
422 *state = HDR_STATE_GOT_CR;
423 break;
424 }
425 }
426 else if (*itr == '\n') {
427 switch (*state) {
428 case HDR_STATE_GOT_LF:
430 break;
431
432 case HDR_STATE_GOT_CR:
433 *state = HDR_STATE_GOT_CRLF;
434 break;
435
438 break;
439
440 default:
441 *state = HDR_STATE_GOT_LF;
442 break;
443 }
444 }
445 else {
447 }
448
449 if (*state == HDR_STATE_DONE_WITH_HEADERS)
450 break;
451
452 ++itr;
453 }
454
455 if (*state == HDR_STATE_DONE_WITH_HEADERS) {
456 return 1;
457 }
458
459 return 0;
460}
461
462/*
463 * handle_response() is based on mod_proxy_fcgi's dispatch()
464 */
469 char *rspbuf,
471{
472 apr_bucket *b;
476 const char *fn = "handle_response";
478 int seen_end_of_headers = 0, done = 0;
479
480 if (rspbuflen) {
482 *rspbuflen = 0; /* unless we actually read something */
483 }
484
486
487 while (!done && rv == APR_SUCCESS) { /* Keep reading FastCGI records until
488 * we get AP_FCGI_END_REQUEST (done)
489 * or an error occurs.
490 */
494 char readbuf[AP_IOBUFSIZE + 1];
495 unsigned char farray[AP_FCGI_HEADER_LEN];
496 unsigned char plen;
497 unsigned char type;
498 unsigned char version;
499
500 rv = recv_data_full(conf, r, s, (char *)farray, AP_FCGI_HEADER_LEN);
501 if (rv != APR_SUCCESS) {
503 APLOGNO(02501) "%s: Error occurred before reading "
504 "entire header", fn);
505 break;
506 }
507
509 farray);
510
511 if (version != AP_FCGI_VERSION_1) {
513 APLOGNO(02502) "%s: Got bogus FastCGI header "
514 "version %d", fn, (int)version);
515 rv = APR_EINVAL;
516 break;
517 }
518
519 if (rid != request_id) {
521 APLOGNO(02503) "%s: Got bogus FastCGI header "
522 "request id %d, expected %d",
523 fn, rid, request_id);
524 rv = APR_EINVAL;
525 break;
526 }
527
528 recv_again: /* if we need to keep reading more of a record's content */
529
530 if (clen > sizeof(readbuf) - 1) {
531 readbuflen = sizeof(readbuf) - 1;
532 } else {
534 }
535
536 /*
537 * Now get the actual content of the record.
538 */
539 if (readbuflen != 0) {
540 rv = recv_data(conf, r, s, readbuf, &readbuflen);
541 if (rv != APR_SUCCESS) {
542 break;
543 }
544 readbuf[readbuflen] = '\0';
545 }
546
547 switch (type) {
548 case AP_FCGI_STDOUT: /* Response headers and optional body */
549 if (clen != 0) {
553
555
556 if (!seen_end_of_headers) {
559
560 if (st == 1) {
561 int status;
562
564
565 status =
567 NULL,
570 APLOGNO(02504) "%s: script header "
571 "parsing -> %d/%d",
572 fn, status, r->status);
573
574 /* FCGI has its own body framing mechanism which we don't
575 * match against any provided Content-Length, so let the
576 * core determine C-L vs T-E based on what's actually sent.
577 */
579 apr_table_unset(r->headers_out, "Content-Length");
580 apr_table_unset(r->headers_out, "Transfer-Encoding");
581
582 if (rspbuf) { /* caller wants to see response body,
583 * if any
584 */
586
587 if (rspbuflen) {
589 }
591 if (tmprv != APR_SUCCESS) {
592 /* should not occur for these bucket types;
593 * does not indicate overflow
594 */
596 APLOGNO(02505) "%s: error "
597 "flattening response body",
598 fn);
599 }
600 }
601
602 if (status != OK) {
603 r->status = status;
605 APLOGNO(02506) "%s: Error parsing "
606 "script headers from %s",
607 fn, conf->backend);
608 rv = APR_EINVAL;
609 break;
610 }
612 }
613 else {
614 /* We're still looking for the end of the
615 * headers, so this part of the data will need
616 * to persist. */
618 }
619 }
620
621 /* If we didn't read all the data go back and get the
622 * rest of it. */
623 if (clen > readbuflen) {
624 clen -= readbuflen;
625 goto recv_again;
626 }
627 }
628 break;
629
630 case AP_FCGI_STDERR: /* Text to log */
631 if (clen) {
633 APLOGNO(02507) "%s: Logged from %s: '%s'",
634 fn, conf->backend, readbuf);
635 }
636
637 if (clen > readbuflen) {
638 clen -= readbuflen;
639 goto recv_again; /* continue reading this record */
640 }
641 break;
642
644 done = 1;
645 break;
646
647 default:
649 APLOGNO(02508) "%s: Got bogus FastCGI record type "
650 "%d", fn, type);
651 break;
652 }
653 /* Leave on above switch's inner error. */
654 if (rv != APR_SUCCESS) {
655 break;
656 }
657
658 /*
659 * Read/discard any trailing padding.
660 */
661 if (plen) {
662 rv = recv_data_full(conf, r, s, readbuf, plen);
663 if (rv != APR_SUCCESS) {
665 APLOGNO(02509) "%s: Error occurred reading "
666 "padding",
667 fn);
668 break;
669 }
670 }
671 }
672
674
675 if (rv == APR_SUCCESS && !seen_end_of_headers) {
676 rv = APR_EINVAL;
678 APLOGNO(02510) "%s: Never reached end of script headers",
679 fn);
680 }
681
682 return rv;
683}
684
685/* almost from mod_fcgid */
686static int mod_fcgid_modify_auth_header(void *vars,
687 const char *key, const char *val)
688{
689 /* When the application gives a 200 response, the server ignores response
690 headers whose names aren't prefixed with Variable- prefix, and ignores
691 any response content */
692 if (ap_cstr_casecmpn(key, "Variable-", 9) == 0)
693 apr_table_setn(vars, key, val);
694 return 1;
695}
696
697static int fix_auth_header(void *vr, const char *key, const char *val)
698{
699 request_rec *r = vr;
700
701 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "moving %s->%s", key, val);
704 return 1;
705}
706
707static void req_rsp(request_rec *r, const fcgi_provider_conf *conf,
708 const char *password, const char *apache_role,
710{
711 const char *fn = "req_rsp";
715 apr_status_t rv;
718
719 if (rspbuflen) {
721 *rspbuflen = 0; /* unless we actually read something */
722 }
723
725 apr_pool_tag(temp_pool, "mod_authnz_fcgi (req_rsp)");
726
728
729 rv = connect_to_peer(&s, r, conf->backend_addrs,
730 conf->backend, FCGI_IO_TIMEOUT);
731 if (rv == APR_SUCCESS) {
733
735 if (rv != APR_SUCCESS) {
737 APLOGNO(02511) "%s: Failed writing request to %s",
738 fn, conf->backend);
739 }
740
741 if (rv == APR_SUCCESS) {
742 rv = send_environment(s, conf, r, request_id, temp_pool);
743 if (rv != APR_SUCCESS) {
745 APLOGNO(02512) "%s: Failed writing environment "
746 "to %s", fn, conf->backend);
747 }
748 }
749
750 /* The responder owns the request body, not the authorizer.
751 * Don't even send an empty AP_FCGI_STDIN block. libfcgi doesn't care,
752 * but it wasn't sent to authorizers by mod_fastcgi or mod_fcgi and
753 * may be unhandled by the app. Additionally, the FastCGI spec does
754 * not mention FCGI_STDIN in the Authorizer description, though it
755 * does describe FCGI_STDIN elsewhere in more general terms than
756 * simply a wrapper for the client's request body.
757 */
758
759 if (rv == APR_SUCCESS) {
760 if (rspbuflen) {
762 }
764 rspbuflen);
765 if (rv != APR_SUCCESS) {
767 APLOGNO(02514) "%s: Failed handling response "
768 "from %s", fn, conf->backend);
769 }
770 }
771
773 }
774
775 if (rv != APR_SUCCESS) {
776 /* some sort of mechanical problem */
778 }
779 else {
781 APLOGNO(02515) "%s: Received HTTP status %d",
782 fn, r->status);
783 }
784
786
787 if (r->status == HTTP_OK) {
788 /* An Authorizer application's 200 response may include headers
789 * whose names are prefixed with Variable-, and they should be
790 * available to subsequent phases via subprocess_env (and yanked
791 * from the client response).
792 */
793 apr_table_t *vars = apr_table_make(temp_pool, /* not used to allocate
794 * any values that end up
795 * in r->(anything)
796 */
797 10);
801 }
802
804}
805
807{
808 const char *fn = "fcgi_check_authn";
810 &authnz_fcgi_module);
811 const char *password = NULL;
812 const fcgi_provider_conf *conf;
813 const char *prov;
814 const char *auth_type;
815 char rspbuf[NON200_RESPONSE_BUF_LEN + 1]; /* extra byte for '\0' */
816 apr_size_t rspbuflen = sizeof rspbuf - 1;
817 int res;
818
819 prov = dconf && dconf->name ? dconf->name : NULL;
820
821 if (!prov || !ap_cstr_casecmp(prov, "None")) {
822 return DECLINED;
823 }
824
826
828 APLOGNO(02516) "%s, prov %s, authoritative %s, "
829 "require-basic %s, user expr? %s type %s",
830 fn, prov,
831 dconf->authoritative ? "yes" : "no",
832 dconf->require_basic_auth ? "yes" : "no",
833 dconf->user_expr ? "yes" : "no",
834 auth_type);
835
836 if (auth_type && !ap_cstr_casecmp(auth_type, "Basic")) {
837 if ((res = ap_get_basic_auth_pw(r, &password))) {
839 APLOGNO(02517) "%s: couldn't retrieve basic auth "
840 "password", fn);
841 if (dconf->require_basic_auth) {
842 return res;
843 }
844 password = NULL;
845 }
846 }
847
849 if (!conf) {
851 APLOGNO(02518) "%s: can't find config for provider %s",
852 fn, prov);
854 }
855
856 if (APLOGrdebug(r)) {
857 log_provider_info(conf, r);
858 }
859
861 rspbuf, &rspbuflen);
862
863 if (r->status == HTTP_OK) {
864 if (dconf->user_expr) {
865 const char *err;
866 const char *user = ap_expr_str_exec(r, dconf->user_expr,
867 &err);
868 if (user && strlen(user)) {
869 r->user = apr_pstrdup(r->pool, user);
871 APLOGNO(02519) "%s: Setting user to '%s'",
872 fn, r->user);
873 }
874 else if (user && dconf->default_user) {
875 r->user = apr_pstrdup(r->pool, dconf->default_user);
876 }
877 else if (user) {
879 APLOGNO(02520) "%s: Failure extracting user "
880 "after calling authorizer: user expression "
881 "yielded empty string (variable not set?)",
882 fn);
884 }
885 else {
886 /* unexpected error, not even an empty string was returned */
888 APLOGNO(02521) "%s: Failure extracting user "
889 "after calling authorizer: %s",
890 fn, err);
892 }
893 }
894 if (conf->is_authz) {
895 /* combined authn/authz phase, so app won't be invoked for authz
896 *
897 * Remember that the request was successfully authorized by this
898 * provider.
899 */
901 rnotes->successful_authnz_provider = conf->name;
902 ap_set_module_config(r->request_config, &authnz_fcgi_module,
903 rnotes);
904 }
905 }
906 else {
907 /* From the spec:
908 * For Authorizer response status values other than "200" (OK), the
909 * Web server denies access and sends the response status, headers,
910 * and content back to the HTTP client.
911 * But:
912 * This only makes sense if this authorizer is authoritative.
913 */
914 if (rspbuflen > 0 && !dconf->authoritative) {
916 APLOGNO(02522) "%s: Ignoring response body from non-"
917 "authoritative authorizer", fn);
918 }
919 else if (rspbuflen > 0) {
920 if (rspbuflen == sizeof rspbuf - 1) {
921 /* apr_brigade_flatten() interface :( */
923 APLOGNO(02523) "%s: possible overflow handling "
924 "response body", fn);
925 }
926 rspbuf[rspbuflen] = '\0'; /* we reserved an extra byte for '\0' */
927 ap_custom_response(r, r->status, rspbuf); /* API makes a copy */
928 }
929 }
930
931 return r->status == HTTP_OK ?
932 OK : dconf->authoritative ? r->status : DECLINED;
933}
934
936 const char *password)
937{
938 const char *fn = "fcgi_check_password";
940 const fcgi_provider_conf *conf;
941
943 APLOGNO(02524) "%s(%s, XXX): provider %s",
944 fn, user, prov);
945
946 if (!prov) {
948 APLOGNO(02525) "%s: provider note isn't set", fn);
949 return AUTH_GENERAL_ERROR;
950 }
951
953 if (!conf) {
955 APLOGNO(02526) "%s: can't find config for provider %s",
956 fn, prov);
957 return AUTH_GENERAL_ERROR;
958 }
959
960 if (APLOGrdebug(r)) {
961 log_provider_info(conf, r);
962 }
963
964 req_rsp(r, conf, password,
965 /* combined authn and authz: FCGI_APACHE_ROLE not set */
967 NULL, NULL);
968
969 if (r->status == HTTP_OK) {
970 if (conf->is_authz) {
971 /* combined authn/authz phase, so app won't be invoked for authz
972 *
973 * Remember that the request was successfully authorized by this
974 * provider.
975 */
977 rnotes->successful_authnz_provider = conf->name;
978 ap_set_module_config(r->request_config, &authnz_fcgi_module,
979 rnotes);
980 }
981 return AUTH_GRANTED;
982 }
983 else if (r->status == HTTP_INTERNAL_SERVER_ERROR) {
984 return AUTH_GENERAL_ERROR;
985 }
986 else {
987 return AUTH_DENIED;
988 }
989}
990
993 NULL /* get-realm-hash not supported */
994};
995
997 const char *require_line,
998 const void *parsed_require_line)
999{
1000 const char *fn = "fcgi_authz_check";
1002 const fcgi_provider_conf *conf;
1003
1005 APLOGNO(02527) "%s(%s)", fn, require_line);
1006
1007 if (!prov) {
1009 APLOGNO(02528) "%s: provider note isn't set", fn);
1010 return AUTHZ_GENERAL_ERROR;
1011 }
1012
1014 if (!conf) {
1016 APLOGNO(02529) "%s: can't find config for provider %s",
1017 fn, prov);
1018 return AUTHZ_GENERAL_ERROR;
1019 }
1020
1021 if (APLOGrdebug(r)) {
1022 log_provider_info(conf, r);
1023 }
1024
1025 if (!r->user) {
1026 return AUTHZ_DENIED_NO_USER;
1027 }
1028
1029 if (conf->is_authn) {
1030 /* combined authn/authz phase, so app won't be invoked for authz
1031 *
1032 * If the provider already successfully authorized this request,
1033 * success.
1034 */
1036 &authnz_fcgi_module);
1037 if (rnotes
1038 && rnotes->successful_authnz_provider
1039 && !strcmp(rnotes->successful_authnz_provider, conf->name)) {
1040 return AUTHZ_GRANTED;
1041 }
1042 else {
1043 return AUTHZ_DENIED;
1044 }
1045 }
1046 else {
1048
1049 if (r->status == HTTP_OK) {
1050 return AUTHZ_GRANTED;
1051 }
1052 else if (r->status == HTTP_INTERNAL_SERVER_ERROR) {
1053 return AUTHZ_GENERAL_ERROR;
1054 }
1055 else {
1056 return AUTHZ_DENIED;
1057 }
1058 }
1059}
1060
1061static const char *fcgi_authz_parse(cmd_parms *cmd, const char *require_line,
1062 const void **parsed_require_line)
1063{
1064 /* Allowed form: Require [not] registered-provider-name<EOS>
1065 */
1066 if (strcmp(require_line, "")) {
1067 return "mod_authnz_fcgi doesn't support restrictions on providers "
1068 "(i.e., multiple require args)";
1069 }
1070
1071 return NULL;
1072}
1073
1078
1080 void *d,
1081 int argc,
1082 char *const argv[])
1083{
1084 const char *dname = "AuthnzFcgiCheckAuthnProvider";
1085 fcgi_dir_conf *dc = d;
1086 int ca = 0;
1087
1088 if (ca >= argc) {
1089 return apr_pstrcat(cmd->pool, dname, ": No provider given", NULL);
1090 }
1091
1092 dc->name = argv[ca];
1093 ca++;
1094
1095 if (!strcasecmp(dc->name, "None")) {
1096 if (ca < argc) {
1097 return "Options aren't supported with \"None\"";
1098 }
1099 }
1100
1101 while (ca < argc) {
1102 const char *var = argv[ca], *val;
1103 int badarg = 0;
1104
1105 ca++;
1106
1107 /* at present, everything needs an argument */
1108 if (ca >= argc) {
1109 return apr_pstrcat(cmd->pool, dname, ": ", var,
1110 "needs an argument", NULL);
1111 }
1112
1113 val = argv[ca];
1114 ca++;
1115
1116 if (!strcasecmp(var, "Authoritative")) {
1117 if (!strcasecmp(val, "On")) {
1118 dc->authoritative = 1;
1119 }
1120 else if (!strcasecmp(val, "Off")) {
1121 dc->authoritative = 0;
1122 }
1123 else {
1124 badarg = 1;
1125 }
1126 }
1127 else if (!strcasecmp(var, "DefaultUser")) {
1128 dc->default_user = val;
1129 }
1130 else if (!strcasecmp(var, "RequireBasicAuth")) {
1131 if (!strcasecmp(val, "On")) {
1132 dc->require_basic_auth = 1;
1133 }
1134 else if (!strcasecmp(val, "Off")) {
1135 dc->require_basic_auth = 0;
1136 }
1137 else {
1138 badarg = 1;
1139 }
1140 }
1141 else if (!strcasecmp(var, "UserExpr")) {
1142 const char *err;
1145
1147 flags, &err, NULL);
1148 if (err) {
1149 return apr_psprintf(cmd->pool, "%s: Error parsing '%s': '%s'",
1150 dname, val, err);
1151 }
1152 }
1153 else {
1154 return apr_pstrcat(cmd->pool, dname, ": Unexpected option '",
1155 var, "'", NULL);
1156 }
1157 if (badarg) {
1158 return apr_pstrcat(cmd->pool, dname, ": Bad argument '",
1159 val, "' to option '", var, "'", NULL);
1160 }
1161 }
1162
1163 return NULL;
1164}
1165
1166/* AuthnzFcgiAuthDefineProvider {authn|authz|authnz} provider-name \
1167 * fcgi://backendhost:backendport/
1168 */
1170 void *d,
1171 int argc,
1172 char *const argv[])
1173{
1174 const char *dname = "AuthnzFcgiDefineProvider";
1176 apr_status_t rv;
1177 char *host;
1178 const char *err, *stype;
1179 fcgi_provider_conf *conf = apr_pcalloc(cmd->pool, sizeof(*conf));
1180 int ca = 0, rc, port;
1181
1183 if (!fcgi_backend_regex) {
1184 return apr_psprintf(cmd->pool,
1185 "%s: failed to compile regexec '%s'",
1187 }
1188
1190 if (err)
1191 return err;
1192
1193 if (ca >= argc) {
1194 return apr_pstrcat(cmd->pool, dname, ": No type given", NULL);
1195 }
1196
1197 stype = argv[ca];
1198 ca++;
1199
1200 if (!strcasecmp(stype, "authn")) {
1201 conf->is_authn = 1;
1202 }
1203 else if (!strcasecmp(stype, "authz")) {
1204 conf->is_authz = 1;
1205 }
1206 else if (!strcasecmp(stype, "authnz")) {
1207 conf->is_authn = conf->is_authz = 1;
1208 }
1209 else {
1210 return apr_pstrcat(cmd->pool,
1211 dname,
1212 ": Invalid provider type ",
1213 stype,
1214 NULL);
1215 }
1216
1217 if (ca >= argc) {
1218 return apr_pstrcat(cmd->pool, dname, ": No provider name given", NULL);
1219 }
1220 conf->name = argv[ca];
1221 ca++;
1222
1223 if (ca >= argc) {
1224 return apr_pstrcat(cmd->pool, dname, ": No backend-address given",
1225 NULL);
1226 }
1227
1229 if (!rc || ap_rxplus_nmatch(fcgi_backend_regex) != 3) {
1230 return apr_pstrcat(cmd->pool,
1231 dname, ": backend-address '",
1232 argv[ca],
1233 "' has invalid form",
1234 NULL);
1235 }
1236
1238 if (host[0] == '[' && host[strlen(host) - 1] == ']') {
1239 host += 1;
1240 host[strlen(host) - 1] = '\0';
1241 }
1242
1244 if (port > 65535) {
1245 return apr_pstrcat(cmd->pool,
1246 dname, ": backend-address '",
1247 argv[ca],
1248 "' has invalid port",
1249 NULL);
1250 }
1251
1252 conf->backend = argv[ca];
1253 conf->host = host;
1254 conf->port = port;
1255 ca++;
1256
1257 rv = apr_sockaddr_info_get(&conf->backend_addrs, conf->host,
1258 APR_UNSPEC, conf->port, 0, cmd->pool);
1259 if (rv != APR_SUCCESS) {
1261 APLOGNO(02530) "Address %s could not be resolved",
1262 conf->backend);
1263 return apr_pstrcat(cmd->pool,
1264 dname,
1265 ": Error resolving backend address",
1266 NULL);
1267 }
1268
1269 if (ca != argc) {
1270 return apr_pstrcat(cmd->pool,
1271 dname,
1272 ": Unexpected parameter ",
1273 argv[ca],
1274 NULL);
1275 }
1276
1277 if (conf->is_authn) {
1279 conf);
1281 conf->name,
1285 }
1286
1287 if (conf->is_authz) {
1289 conf);
1291 conf->name,
1295 }
1296
1297 return NULL;
1298}
1299
1300static const command_rec fcgi_cmds[] = {
1301 AP_INIT_TAKE_ARGV("AuthnzFcgiDefineProvider",
1303 NULL,
1304 RSRC_CONF,
1305 "Define a FastCGI authn and/or authz provider"),
1306
1307 AP_INIT_TAKE_ARGV("AuthnzFcgiCheckAuthnProvider",
1309 NULL,
1311 "Enable/disable a FastCGI authorizer to handle "
1312 "check_authn phase"),
1313
1314 {NULL}
1315};
1316
1325
1327{
1328 static const char * const auth_basic_runs_after_me[] =
1329 {"mod_auth_basic.c", NULL}; /* to allow for custom response */
1330
1334}
1335
1336static void *create_dir_conf(apr_pool_t *p, char *dummy)
1337{
1338 fcgi_dir_conf *dconf = apr_pcalloc(p, sizeof(fcgi_dir_conf));
1339
1340 dconf->authoritative = 1;
1341 return dconf;
1342}
1343
1344static void *merge_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
1345{
1346 fcgi_dir_conf *a = (fcgi_dir_conf *)apr_pcalloc(p, sizeof(*a));
1349
1350 /* currently we just have a single directive applicable to a
1351 * directory, so if it is set then grab all fields from fcgi_dir_conf
1352 */
1353 if (over->name) {
1354 memcpy(a, over, sizeof(*a));
1355 }
1356 else {
1357 memcpy(a, base, sizeof(*a));
1358 }
1359
1360 return a;
1361}
1362
1364{
1366 create_dir_conf, /* dir config creater */
1367 merge_dir_conf, /* dir merger */
1368 NULL, /* server config */
1369 NULL, /* merge server config */
1370 fcgi_cmds, /* command apr_table_t */
1371 fcgi_register_hooks /* register hooks */
1372};
Module Magic Number.
Apache Provider API.
int n
Definition ap_regex.h:278
#define ap_rxplus_nmatch(rx)
Definition ap_regex.h:267
const char apr_size_t len
Definition ap_regex.h:187
APR Hash Tables.
APR general purpose library routines.
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
static apr_pool_t * pconf
Definition event.c:441
#define ap_get_module_config(v, m)
#define AP_INIT_TAKE_ARGV(directive, func, mconfig, where, help)
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
#define ap_set_module_config(v, m, val)
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
request_rec * r
#define AP_IOBUFSIZE
Definition httpd.h:306
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define AP_FCGI_APACHE_ROLE_AUTHENTICATOR_STR
Definition util_fcgi.h:271
void ap_fcgi_fill_in_header(ap_fcgi_header *header, unsigned char type, apr_uint16_t request_id, apr_uint16_t content_len, unsigned char padding_len)
Definition util_fcgi.c:81
#define AP_FCGI_AUTHORIZER
Definition util_fcgi.h:126
apr_size_t ap_fcgi_encoded_env_len(apr_table_t *env, apr_size_t maxlen, int *starting_elem)
Definition util_fcgi.c:116
#define AP_FCGI_VERSION_1
Definition util_fcgi.h:72
void ap_fcgi_fill_in_request_body(ap_fcgi_begin_request_body *brb, int role, unsigned char flags)
Definition util_fcgi.c:102
void ap_fcgi_header_fields_from_array(unsigned char *version, unsigned char *type, apr_uint16_t *request_id, apr_uint16_t *content_len, unsigned char *padding_len, unsigned char a[])
Definition util_fcgi.c:52
#define AP_FCGI_HEADER_LEN
Definition util_fcgi.h:62
#define AP_FCGI_STDERR
Definition util_fcgi.h:83
void ap_fcgi_header_to_array(ap_fcgi_header *h, unsigned char a[])
Definition util_fcgi.c:26
#define AP_FCGI_END_REQUEST
Definition util_fcgi.h:79
apr_status_t ap_fcgi_encode_env(request_rec *r, apr_table_t *env, void *buffer, apr_size_t buflen, int *starting_elem)
Definition util_fcgi.c:179
#define AP_FCGI_APACHE_ROLE_AUTHORIZER_STR
Definition util_fcgi.h:272
#define AP_FCGI_AUTHORIZER_STR
Definition util_fcgi.h:261
#define AP_FCGI_BEGIN_REQUEST
Definition util_fcgi.h:77
#define AP_FCGI_STDOUT
Definition util_fcgi.h:82
#define AP_FCGI_PARAMS
Definition util_fcgi.h:80
void ap_fcgi_begin_request_body_to_array(ap_fcgi_begin_request_body *h, unsigned char a[])
Definition util_fcgi.c:68
void ap_custom_response(request_rec *r, int status, const char *string)
Definition core.c:1648
const char * ap_auth_type(request_rec *r)
Definition core.c:793
#define AP_LOG_DATA_SHOW_OFFSET
Definition http_log.h:569
#define APLOGNO(n)
Definition http_log.h:117
#define APLOGrdebug(r)
Definition http_log.h:245
#define APLOG_STARTUP
Definition http_log.h:105
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_R_IS_LEVEL(r, level)
Definition http_log.h:229
#define ap_log_rdata
Definition http_log.h:642
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOG_TRACE5
Definition http_log.h:76
#define APLOG_DEBUG
Definition http_log.h:71
#define APLOG_MODULE_INDEX
Definition http_log.h:168
const unsigned char * buf
Definition util_md5.h:50
int ap_get_basic_auth_pw(request_rec *r, const char **pw)
Definition protocol.c:1758
apr_status_t ap_register_auth_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, const char *provider_version, const void *provider, int type)
Definition request.c:2179
#define AP_AUTH_INTERNAL_PER_CONF
void ap_hook_check_authn(ap_HOOK_check_user_id_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder, int type)
Definition request.c:2218
void ap_add_common_vars(request_rec *r)
int ap_scan_script_header_err_brigade_ex(request_rec *r, apr_bucket_brigade *bb, char *buffer, int module_index)
void ap_add_cgi_vars(request_rec *r)
#define AP_TRUST_CGILIKE_CL_ENVVAR
const char apr_port_t port
Definition http_vhost.h:125
void * dummy
Definition http_vhost.h:62
const char * host
Definition http_vhost.h:124
#define APR_EINVAL
Definition apr_errno.h:711
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define apr_bucket_setaside(e, p)
apr_bucket apr_bucket_brigade * a
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
const char apr_ssize_t int flags
Definition apr_encode.h:168
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
apr_pool_t * temp_pool
apr_redis_t * rc
Definition apr_redis.h:173
#define AP_EXPR_FLAG_DONT_VARY
Definition ap_expr.h:61
#define AP_EXPR_FLAG_STRING_RESULT
Definition ap_expr.h:68
#define ap_expr_parse_cmd(cmd, expr, flags, err, lookup_fn)
Definition ap_expr.h:340
const char * ap_expr_str_exec(request_rec *r, const ap_expr_info_t *expr, const char **err)
#define AP_EXPR_FLAG_RESTRICTED
Definition ap_expr.h:66
#define RSRC_CONF
#define OR_FILEINFO
#define HTTP_OK
Definition httpd.h:490
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define STANDARD20_MODULE_STUFF
int ap_cstr_casecmp(const char *s1, const char *s2)
Definition util.c:3542
int ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n)
Definition util.c:3559
#define ap_assert(exp)
Definition httpd.h:2271
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
const struct iovec * vec
apr_seek_where_t apr_off_t * offset
int type
const struct iovec apr_size_t nvec
int strcasecmp(const char *a, const char *b)
apr_pool_t int argc
Definition apr_getopt.h:104
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
apr_sockaddr_t * addr
apr_size_t buflen
apr_uint16_t apr_port_t
#define APR_UNSPEC
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
#define APR_TCP_NODELAY
const char * s
Definition apr_strings.h:95
int nelts
Definition apr_tables.h:122
const char const char * password
apr_int32_t apr_int32_t apr_int32_t err
apr_cmdtype_e cmd
int int status
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
Authentication and Authorization Extension for Apache.
#define AUTHN_PROVIDER_NAME_NOTE
Definition mod_auth.h:45
#define AUTHN_PROVIDER_VERSION
Definition mod_auth.h:41
#define AUTHN_PROVIDER_GROUP
Definition mod_auth.h:39
authz_status
Definition mod_auth.h:72
@ AUTHZ_DENIED
Definition mod_auth.h:73
@ AUTHZ_GENERAL_ERROR
Definition mod_auth.h:76
@ AUTHZ_DENIED_NO_USER
Definition mod_auth.h:77
@ AUTHZ_GRANTED
Definition mod_auth.h:74
#define AUTHZ_PROVIDER_NAME_NOTE
Definition mod_auth.h:46
authn_status
Definition mod_auth.h:64
@ AUTH_GRANTED
Definition mod_auth.h:66
@ AUTH_DENIED
Definition mod_auth.h:65
@ AUTH_GENERAL_ERROR
Definition mod_auth.h:69
#define AUTHZ_PROVIDER_VERSION
Definition mod_auth.h:42
#define AUTHZ_PROVIDER_GROUP
Definition mod_auth.h:40
static int handle_headers(request_rec *r, int *state, const char *readbuf, apr_size_t readlen)
static const char * fcgi_define_provider(cmd_parms *cmd, void *d, int argc, char *const argv[])
static const char * fcgi_authz_parse(cmd_parms *cmd, const char *require_line, const void **parsed_require_line)
static void * merge_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
static authz_status fcgi_authz_check(request_rec *r, const char *require_line, const void *parsed_require_line)
#define NON200_RESPONSE_BUF_LEN
#define FCGI_BACKEND_REGEX_STR
static int fix_auth_header(void *vr, const char *key, const char *val)
static int mod_fcgid_modify_auth_header(void *vars, const char *key, const char *val)
static void setupenv(request_rec *r, const char *password, const char *apache_role)
static int fcgi_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
#define FCGI_IO_TIMEOUT
static void log_provider_info(const fcgi_provider_conf *conf, request_rec *r)
static apr_status_t send_begin_request(request_rec *r, const fcgi_provider_conf *conf, apr_socket_t *s, int role, apr_uint16_t request_id)
static const authz_provider fcgi_authz_provider
static const command_rec fcgi_cmds[]
static const char * fcgi_check_authn_provider(cmd_parms *cmd, void *d, int argc, char *const argv[])
static int fcgi_check_authn(request_rec *r)
static apr_status_t connect_to_peer(apr_socket_t **newsock, request_rec *r, apr_sockaddr_t *backend_addrs, const char *backend_name, apr_interval_time_t timeout)
static void fcgi_register_hooks(apr_pool_t *p)
static void * create_dir_conf(apr_pool_t *p, char *dummy)
static apr_status_t handle_response(const fcgi_provider_conf *conf, request_rec *r, apr_socket_t *s, apr_pool_t *temp_pool, apr_uint16_t request_id, char *rspbuf, apr_size_t *rspbuflen)
static void req_rsp(request_rec *r, const fcgi_provider_conf *conf, const char *password, const char *apache_role, char *rspbuf, apr_size_t *rspbuflen)
@ HDR_STATE_GOT_CRLFCR
@ HDR_STATE_READING_HEADERS
@ HDR_STATE_DONE_WITH_HEADERS
@ HDR_STATE_GOT_CRLF
@ HDR_STATE_GOT_LF
@ HDR_STATE_GOT_CR
static apr_status_t sendv_data(const fcgi_provider_conf *conf, request_rec *r, apr_socket_t *s, struct iovec *vec, int nvec, apr_size_t *len)
static apr_status_t send_environment(apr_socket_t *s, const fcgi_provider_conf *conf, request_rec *r, apr_uint16_t request_id, apr_pool_t *temp_pool)
static authn_status fcgi_check_password(request_rec *r, const char *user, const char *password)
static apr_status_t recv_data(const fcgi_provider_conf *conf, request_rec *r, apr_socket_t *s, char *buf, apr_size_t *buflen)
static const authn_provider fcgi_authn_provider
static apr_hash_t * fcgi_authz_providers
static apr_hash_t * fcgi_authn_providers
static apr_status_t recv_data_full(const fcgi_provider_conf *conf, request_rec *r, apr_socket_t *s, char *buf, apr_size_t buflen)
const char * argv[3]
header_state
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
This represents the content data of the FastCGI record when the type is AP_FCGI_BEGIN_REQUEST.
Definition util_fcgi.h:106
A structure that represents the fixed header fields at the beginning of a "FastCGI record" (i....
Definition util_fcgi.h:40
apr_sockaddr_t * next
apr_int32_t family
Definition apr_tables.h:81
char * val
Definition apr_tables.h:87
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
const char * default_user
ap_expr_info_t * user_expr
const char * name
apr_sockaddr_t * backend_addrs
const char * successful_authnz_provider
A structure that represents the current request.
Definition httpd.h:845
char * user
Definition httpd.h:1005
int status
Definition httpd.h:891
apr_table_t * notes
Definition httpd.h:985
apr_pool_t * pool
Definition httpd.h:847
conn_rec * connection
Definition httpd.h:849
apr_table_t * err_headers_out
Definition httpd.h:981
struct ap_conf_vector_t * request_config
Definition httpd.h:1049
apr_table_t * subprocess_env
Definition httpd.h:983
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
apr_table_t * headers_out
Definition httpd.h:978
A structure to keep track of authorization requirements.
Definition http_core.h:316
apr_interval_time_t timeout
Definition httpd.h:1372
apr_status_t apr_socket_sendv(apr_socket_t *sock, const struct iovec *vec, apr_int32_t nvec, apr_size_t *len)
Definition sendrecv.c:194
apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
Definition sendrecv.c:70
apr_status_t apr_socket_close(apr_socket_t *thesocket)
Definition sockets.c:211
apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa)
Definition sockets.c:388
apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, int protocol, apr_pool_t *cont)
Definition sockets.c:116
apr_status_t apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
Definition sockopt.c:113
apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
Definition sockopt.c:75
#define var
FastCGI protocol definitions and support routines.
int ap_rxplus_exec(apr_pool_t *pool, ap_rxplus_t *rx, const char *pattern, char **newpattern)
Definition util_regex.c:141
char * ap_rxplus_pmatch(apr_pool_t *pool, ap_rxplus_t *rx, int n)
Definition util_regex.c:205
ap_rxplus_t * ap_rxplus_compile(apr_pool_t *pool, const char *pattern)
Definition util_regex.c:31
Apache script tools.
IN ULONG IN INT timeout