1 /*	$OpenBSD: mod_log_agent.c,v 1.8 2004/12/02 19:42:48 henning Exp $ */
2 
3 /* ====================================================================
4  * The Apache Software License, Version 1.1
5  *
6  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
7  * reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. The end-user documentation included with the redistribution,
22  *    if any, must include the following acknowledgment:
23  *       "This product includes software developed by the
24  *        Apache Software Foundation (http://www.apache.org/)."
25  *    Alternately, this acknowledgment may appear in the software itself,
26  *    if and wherever such third-party acknowledgments normally appear.
27  *
28  * 4. The names "Apache" and "Apache Software Foundation" must
29  *    not be used to endorse or promote products derived from this
30  *    software without prior written permission. For written
31  *    permission, please contact apache@apache.org.
32  *
33  * 5. Products derived from this software may not be called "Apache",
34  *    nor may "Apache" appear in their name, without prior written
35  *    permission of the Apache Software Foundation.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals on behalf of the Apache Software Foundation.  For more
53  * information on the Apache Software Foundation, please see
54  * <http://www.apache.org/>.
55  *
56  * Portions of this software are based upon public domain software
57  * originally written at the National Center for Supercomputing Applications,
58  * University of Illinois, Urbana-Champaign.
59  */
60 
61 
62 #include "httpd.h"
63 #include "http_config.h"
64 #include "http_log.h"
65 #include "http_main.h"
66 #include "fdcache.h"
67 
68 module agent_log_module;
69 
70 static int xfer_flags = (O_WRONLY | O_APPEND | O_CREAT);
71 static mode_t xfer_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
72 
73 typedef struct {
74     char *fname;
75     int agent_fd;
76 } agent_log_state;
77 
make_agent_log_state(pool * p,server_rec * s)78 static void *make_agent_log_state(pool *p, server_rec *s)
79 {
80     agent_log_state *cls =
81     (agent_log_state *) ap_palloc(p, sizeof(agent_log_state));
82 
83     cls->fname = "";
84     cls->agent_fd = -1;
85 
86     return (void *) cls;
87 }
88 
set_agent_log(cmd_parms * parms,void * dummy,char * arg)89 static const char *set_agent_log(cmd_parms *parms, void *dummy, char *arg)
90 {
91     agent_log_state *cls = ap_get_module_config(parms->server->module_config,
92                                              &agent_log_module);
93 
94     cls->fname = arg;
95     return NULL;
96 }
97 
98 static const command_rec agent_log_cmds[] =
99 {
100     {"AgentLog", set_agent_log, NULL, RSRC_CONF, TAKE1,
101      "the filename of the agent log"},
102     {NULL}
103 };
104 
open_agent_log(server_rec * s,pool * p)105 static void open_agent_log(server_rec *s, pool *p)
106 {
107     agent_log_state *cls = ap_get_module_config(s->module_config,
108                                              &agent_log_module);
109 
110     char *fname = ap_server_root_relative(p, cls->fname);
111 
112     if (cls->agent_fd > 0)
113         return;                 /* virtual log shared w/main server */
114 
115     if (*cls->fname == '|') {
116         piped_log *pl;
117 
118         pl = ap_open_piped_log(p, cls->fname + 1);
119         if (pl == NULL) {
120 	    ap_log_error(APLOG_MARK, APLOG_ERR, s,
121 			 "couldn't spawn agent log pipe");
122             exit(1);
123         }
124         cls->agent_fd = ap_piped_log_write_fd(pl);
125     }
126     else if (*cls->fname != '\0') {
127 	if (ap_server_chroot_desired())
128 	    cls->agent_fd = fdcache_open(fname, xfer_flags, xfer_mode);
129 	else
130 	    cls->agent_fd = ap_popenf_ex(p, fname, xfer_flags, xfer_mode, 1);
131 
132         if (cls->agent_fd < 0) {
133             ap_log_error(APLOG_MARK, APLOG_ERR, s,
134                          "could not open agent log file %s.", fname);
135             exit(1);
136         }
137     }
138 }
139 
init_agent_log(server_rec * s,pool * p)140 static void init_agent_log(server_rec *s, pool *p)
141 {
142     for (; s; s = s->next)
143         open_agent_log(s, p);
144 }
145 
agent_log_transaction(request_rec * orig)146 static int agent_log_transaction(request_rec *orig)
147 {
148     agent_log_state *cls = ap_get_module_config(orig->server->module_config,
149                                              &agent_log_module);
150 
151     char str[HUGE_STRING_LEN];
152     const char *agent;
153     request_rec *r;
154 
155     if (cls->agent_fd < 0)
156         return OK;
157 
158     for (r = orig; r->next; r = r->next)
159         continue;
160     if (*cls->fname == '\0')    /* Don't log agent */
161         return DECLINED;
162 
163     agent = ap_table_get(orig->headers_in, "User-Agent");
164     if (agent != NULL) {
165         snprintf(str, sizeof(str), "%s\n", agent);
166         write(cls->agent_fd, str, strlen(str));
167     }
168 
169     return OK;
170 }
171 
172 module agent_log_module =
173 {
174     STANDARD_MODULE_STUFF,
175     init_agent_log,             /* initializer */
176     NULL,                       /* create per-dir config */
177     NULL,                       /* merge per-dir config */
178     make_agent_log_state,       /* server config */
179     NULL,                       /* merge server config */
180     agent_log_cmds,             /* command table */
181     NULL,                       /* handlers */
182     NULL,                       /* filename translation */
183     NULL,                       /* check_user_id */
184     NULL,                       /* check auth */
185     NULL,                       /* check access */
186     NULL,                       /* type_checker */
187     NULL,                       /* fixups */
188     agent_log_transaction,      /* logger */
189     NULL,                       /* header parser */
190     NULL,                       /* child_init */
191     NULL,                       /* child_exit */
192     NULL                        /* post read-request */
193 };
194