1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
|
.Dd August 12, 2020
.Dt STERNENBLOG.CGI 1
.Os
.Sh NAME
.Nm sternenblog.cgi
.Nd file based CGI blog software
.Sh SYNOPSIS
.Nm sternenblog.cgi
.Sh DESCRIPTION
The
.Nm
CGI script implements a blog application based on a directory containing blog
entries in HTML format.
It serves both an index page listing all available entries and single pages for
every individual entry.
.Pp
The Request URL
.Ql /sternenblog.cgi
results in the index page being served,
.Ql /sternenblog.cgi/rss.xml
returns a RSS feed with the same contents as the index page, likewise
.Ql /sternenblog.cgi/atom.xml
an atom feed and finally
.Ql /sternenblog.cgi/<my-entry>
serves the single entry page for
.Pa /path/to/entry/directory/<my-entry> .
.Pp
Every entry is a regular file in the configured entry directory that meets
certain criteria (see
.Sx "SECURITY CONSIDERATIONS"
for details) and should contain a HTML snippet which is passed to the
used template by
.Nm
to generate a complete HTML page.
To determine the “publication” datetime of an entry and to sort the index
page, the modification time of the underlying file is used.
To backdate an entry (for example after a minor edit)
.Xr touch 1
can be used to (re)set the modification time.
.Ss CONFIGURATION
.Nm
is configured statically by changing
.Pa config.h
before (re)compiling it.
If no custom config header is provided at compile time,
it is generated from the default one,
.Pa config.example.h ,
which also may serve as a starting point for a custom configuration.
.Bl -tag -width Ds
.It Sy BLOG_DIR
The directory blog entries are stored in.
See
.Sx "SECURITY CONSIDERATIONS"
for information on which files in that directory are processed by
.Nm .
It is recommended to use a dedicated directory owned by the webserver's
user and group which only contains the blog entries without a (sub)directory
structure.
.Pp
Must either start with
.Ql ./
or
.Ql /
although the latter, i. e. an absolute path, is recommended.
.Pp
Default value is
.Pa /srv/sternenblog/ .
.It Sy BLOG_SERVER_URL
Public URL of the root of the server, i. e. public address or hostname and used
protocol.
This is used to construct global URLs to the entries for the RSS and Atom
feeds.
.Pp
Default value is
.Ql http://localhost .
.It Sy BLOG_STRICT_ACCESS
If set to
.Ql 1
.Nm
will check if a file is either owned by the process's user or group before
serving it.
If it isn't, a 403 Forbidden error response will be generated.
This is useful if you want to make it harder for yourself to
publish entries by accident.
Setting it to
.Ql 0
will disable the check.
.Pp
Default value is
.Ql 1 .
.It Sy BLOG_TITLE
Title of the blog to serve, used in the RSS feed and the default template.
.Pp
Default value is
.Ql my blog .
.It Sy BLOG_AUTHOR
Used to set the
.Ql name
element of the Atom feed's
.Ql author
element.
Should contain the (human readable) name of the blog's author.
.Pp
This value is optional: If it's missing
.Nm
will use the username it is running as.
.Pp
Default value is
.Ql Jane Doe .
.It Sy BLOG_DESCRIPTION
Used to set the
.Ql description
element of the RSS and Atom feeds.
.Pp
Default value is
.Ql my personal blog .
.It Sy BLOG_CACHE_MAX_AGE
Used to determine the value of
.Ql max-age
in the
.Ql Cache-Control
HTTP/1.1 header.
The
.Ql max-age
is the number of seconds a response from the webserver is considered “fresh”.
This roughly equates to the time a web browser will not request the same page
again, but use the version from its cache. After that the cache might still be
used, but the browser will try to find out if it changed (in this case
.Nm
will always reissue the response even if it did not change, since it doesn't
support
.Ql ETag
and the likes).
.Pp
Setting this option can help reduce server load: If someone is browsing the
served blog, the index page won't be regenerated every time they come back to
it, but served from their browsers cache. Therefore the value should be longer
than you expect users to spend time on your site.
.Pp
This value is optional: If not set, the
.Ql
Cache-Control
header is not sent.
.Pp
Default value is
.Ql 3600 .
.It Sy BLOG_CSS
Absolute path from the web root to the CSS stylesheet to be used by the default
template.
See
.Sx FILES
for the location of the installed default stylesheet.
.Pp
This value is optional: If not set, no stylesheet is included.
.Pp
Default value is
.Ql /sternenblog.css
.El
.Pp
It is also possible to add additional values to
.Pa config.h
to be used in a custom template.
.Pp
The template can be changed in
.Pa config.mk
by changing the
.Ql TEMPLATE
variable to the path to the template file without its extension.
For details
refer to section
.Sx TEMPLATING .
.Ss BUILDING
.Nm
is built using
.Xr make 1 .
.Pp
The default target compiles
.Nm
using
.Sy CC
and the
.Sy CFLAGS
set in
.Pa config.mk
and generates
.Pa config.h
from
.Pa config.example.h
beforehand if it is missing.
.Pp
In most, if not all, cases it is required to provide a custom
.Pa config.h
or to change
.Pa config.example.h
prior to compiling for
.Nm
to work properly.
For details refer to the previous section
.Sx CONFIGURATION .
.Pp
The
.Ql doc
target builds developer documentation about templating, provided helper
libraries and
.Nm
internals using
.Xr doxygen 1 .
The output can be found in
.Pa doc/html
and
.Pa doc/man/man3
in HTML and man page format respectively.
.Pp
The
.Ql install
target installs
documentation and files necessary for serving
.Nm sternenblog.cgi
to
.Pa /usr/local .
If
.Pa assets/favicon.ico
is missing, a default one is generated using
.Xr convert 1 .
All files intended to be served by a web server are
installed to
.Pa /usr/local/share/sternenblog .
For a listing of files installed apart from
documentation and the CGI script itself see section
.Sx FILES .
All installation paths can be adjusted in
.Pa config.mk
\".Ss WEBSERVER CONFIGURATION TODO
.
.Ss TEMPLATING
See
.Xr template.h 3
.
.Sh ENVIRONMENT
.Nm
expects a subset of the CGI 1.1 environment as specified in
.Lk https://tools.ietf.org/html/rfc3875 RFC3876 .
The expected variables to be set are:
.Bl -tag -width Ds
.It Ev SCRIPT_NAME
Expected to be the script name as an absolute path from the webroot, i. e\.
.Ql <a href="$SCRIPT_NAME">index</a>
is expected to link to the script itself, so
.Ev PATH_INFO
is empty and the index page is served.
.It Ev PATH_INFO
Is expected to be the URL part after
.Ev SCRIPT_NAME ,
i. e. the path to a subpage of the script.
This is interpreted as a path to an entry and must start with a leading
.Ql / .
.El
.Pp
Most likely these will be set correctly by your favorite web server without
any special configuration.
.Sh FILES AND DIRECTORIES
Below is a listing of files and directories used and installed by default.
It is possible to configure
.Nm
to use different locations instead as described in section
.Sx CONFIGURATION .
.Bl -tag -width Ds
.It Pa /srv/sternenblog
Default directory for entries used by
.Nm .
Controlled by
.Ql BLOG_DIR
in
.Pa config.h .
Not created by the installation process.
.It Pa /usr/share/sternenblog/sternenblog.css
Default CSS the default template of
.Nm
uses.
If used, must be served at
.Pa /sternenblog.css
by the used web server.
Controlled by
.Ql BLOG_CSS
in
.Pa config.h .
.It Pa /usr/share/sternenblog/favicon.ico
Default favicon of
.Nm .
Can optionally be served at
.Pa /favicon.ico
by the used web server.
.El
.Sh EXIT STATUS
.Nm
always returns 0.
Errors are reported via the HTTP
.Ql Status
header.
.Sh SEE ALSO
.Xr cgiutil.h 3 ,
.Xr config.example.h 3 ,
.Xr core.h 3 ,
.Xr entry.h 3 ,
.Xr index.h 3 ,
.Xr main.c 3 ,
.Xr template.h 3 and
.Xr xml.h 3 .
.Sh AUTHORS
.An sternenseemann <sternenseemann@systemli.org>
.\" .Sh LIMITATIONS TODO
.Sh "SECURITY CONSIDERATIONS"
.Nm
hasn't been tested thoroughly in production yet and, as it is a one person
project, no second pair of eyes has reviewed the code.
There may well be issues that haven't been discovered yet.
.Pp
User input comes from two avenues: The first one is trusted:
blog entries stored in the configured directory.
The second one is arbitrary user input from third parties via
.Ev PATH_INFO .
.Pp
.Ev PATH_INFO
is validated to prevent
.Nm
from accessing dotfiles and escaping from the configured directory by using
.Ql .. .
Although the latter usually is already mitigated by the web server's
processing of the request URL.
.Pp
While accessing files,
.Nm
will only process regular files (e. g. not follow symlinks) and make sure that
the file is either owned by the group or the user it is running as (which will
usually be the webserver's user and group).
The check is made using the effective UID and GID which are determined using
.Xr geteuid 2 and
.Xr getegid 2 .
The idea here is that
.Xr chown 1
has to be used actively for the entry files to be processed by
.Nm .
Note that this check can be disabled via the
.Sx CONFIGURATION
of
.Nm .
.Pp
.Nm
will process files in subdirectories of the configured directory if they are
addressed directly.
They will however not be part of any indices or listings.
This behavior might be subject to change in the future.
|