~ubuntu-branches/ubuntu/warty/lynx/warty-security

« back to all changes in this revision

Viewing changes to src/LYCgi.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-16 12:14:10 UTC
  • Revision ID: james.westby@ubuntu.com-20040916121410-cz1gu92c4nqfeyrg
Tags: upstream-2.8.5
ImportĀ upstreamĀ versionĀ 2.8.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*                   Lynx CGI support                              LYCgi.c
 
2
**                   ================
 
3
**
 
4
** Authors
 
5
**          GL      George Lindholm <George.Lindholm@ubc.ca>
 
6
**
 
7
** History
 
8
**      15 Jun 95   Created as way to provide a lynx based service with
 
9
**                  dynamic pages without the need for a http daemon.  GL
 
10
**      27 Jun 95   Added <index> (command line) support.  Various cleanup
 
11
**                  and bug fixes. GL
 
12
**      04 Sep 97   Added support for PATH_INFO scripts.  JKT
 
13
**
 
14
** Bugs
 
15
**      If the called scripts aborts before sending the mime headers then
 
16
**      lynx hangs.
 
17
**
 
18
**      Should do something about SIGPIPE, (but then it should never happen)
 
19
**
 
20
**      No support for redirection.  Or mime-types.
 
21
**
 
22
**      Should try and parse for a HTTP 1.1 header in case we are "calling" a
 
23
**      nph- script.
 
24
*/
 
25
 
 
26
#include <HTUtils.h>
 
27
#include <HTTP.h>
 
28
#include <HTParse.h>
 
29
#include <HTTCP.h>
 
30
#include <HTFormat.h>
 
31
#include <HTFile.h>
 
32
#include <HTAlert.h>
 
33
#include <HTMIME.h>
 
34
#include <HTAABrow.h>
 
35
 
 
36
#include <LYGlobalDefs.h>
 
37
#include <LYUtils.h>
 
38
#include <HTML.h>
 
39
#include <HTInit.h>
 
40
#include <LYGetFile.h>
 
41
#include <LYBookmark.h>
 
42
#include <GridText.h>
 
43
#include <LYCgi.h>
 
44
#include <LYStrings.h>
 
45
#include <LYLocal.h>
 
46
 
 
47
#include <LYLeaks.h>
 
48
#include <www_wait.h>
 
49
 
 
50
struct _HTStream
 
51
{
 
52
  HTStreamClass * isa;
 
53
};
 
54
 
 
55
PRIVATE char **env = NULL;  /* Environment variables */
 
56
PRIVATE int envc_size = 0;  /* Slots in environment array */
 
57
PRIVATE int envc = 0;       /* Slots used so far */
 
58
PRIVATE HTList *alloced = NULL;
 
59
#ifdef LYNXCGI_LINKS
 
60
PRIVATE char *user_agent = NULL;
 
61
PRIVATE char *server_software = NULL;
 
62
PRIVATE char *accept_language = NULL;
 
63
PRIVATE char *post_len = NULL;
 
64
#endif /* LYNXCGI_LINKS */
 
65
 
 
66
PRIVATE void add_environment_value PARAMS((char *env_value));
 
67
 
 
68
#define PERROR(msg) CTRACE((tfp, "LYNXCGI: %s: %s\n", msg, LYStrerror(errno)))
 
69
 
 
70
#ifdef LY_FIND_LEAKS
 
71
PRIVATE void free_alloced_lynxcgi NOARGS
 
72
{
 
73
    void *ptr;
 
74
    while ((ptr = HTList_removeLastObject(alloced)) != NULL) {
 
75
        FREE(ptr);
 
76
    }
 
77
    FREE(alloced);
 
78
#ifdef LYNXCGI_LINKS
 
79
    FREE(user_agent);
 
80
    FREE(server_software);
 
81
#endif
 
82
}
 
83
#endif /* LY_FIND_LEAKS */
 
84
 
 
85
PRIVATE void remember_alloced ARGS1(
 
86
    void *,             ptr)
 
87
{
 
88
    if (!alloced) {
 
89
        alloced = HTList_new();
 
90
#ifdef LY_FIND_LEAKS
 
91
        atexit(free_alloced_lynxcgi);
 
92
#endif
 
93
    }
 
94
    HTList_addObject(alloced, ptr);
 
95
}
 
96
 
 
97
/*
 
98
 * Simple routine for expanding the environment array and adding a value to
 
99
 * it
 
100
 */
 
101
PRIVATE void add_environment_value ARGS1(
 
102
        char *, env_value)
 
103
{
 
104
    if (envc == envc_size) {   /* Need some more slots */
 
105
        envc_size += 10;
 
106
        if (env) {
 
107
            env = (char **)realloc(env,
 
108
                                   sizeof(env[0]) * (envc_size + 2));
 
109
                                                /* + terminator and base 0 */
 
110
        } else {
 
111
            env = (char **)malloc(sizeof(env[0]) * (envc_size + 2));
 
112
                                                /* + terminator and base 0 */
 
113
            remember_alloced(env);
 
114
        }
 
115
        if (env == NULL) {
 
116
            outofmem(__FILE__, "LYCgi");
 
117
        }
 
118
    }
 
119
 
 
120
    env[envc++] = env_value;
 
121
    env[envc] = NULL;      /* Make sure it is always properly terminated */
 
122
}
 
123
 
 
124
/*
 
125
 * Add the value of an existing environment variable to those passed on to the
 
126
 * lynxcgi script.
 
127
 */
 
128
PUBLIC void add_lynxcgi_environment ARGS1(
 
129
        CONST char *,   variable_name)
 
130
{
 
131
    char *env_value;
 
132
 
 
133
    env_value = LYGetEnv(variable_name);
 
134
    if (env_value != NULL) {
 
135
        char *add_value = NULL;
 
136
 
 
137
        HTSprintf0(&add_value, "%s=%s", variable_name, env_value);
 
138
        add_environment_value(add_value);
 
139
        remember_alloced(add_value);
 
140
    }
 
141
}
 
142
 
 
143
#ifdef __MINGW32__
 
144
PRIVATE int LYLoadCGI ARGS4(
 
145
        CONST char *,           arg,
 
146
        HTParentAnchor *,       anAnchor,
 
147
        HTFormat,               format_out,
 
148
        HTStream*,              sink)
 
149
{
 
150
        return -1;
 
151
}
 
152
#else
 
153
PRIVATE int LYLoadCGI ARGS4(
 
154
        CONST char *,           arg,
 
155
        HTParentAnchor *,       anAnchor,
 
156
        HTFormat,               format_out,
 
157
        HTStream*,              sink)
 
158
{
 
159
    int status = 0;
 
160
#ifdef LYNXCGI_LINKS
 
161
#ifndef VMS
 
162
    char *cp;
 
163
    struct stat stat_buf;
 
164
    char *pgm = NULL;                   /* executable */
 
165
    char *pgm_args = NULL;              /* and its argument(s) */
 
166
    int statrv;
 
167
    char *orig_pgm = NULL;              /* Path up to ? as given, URL-escaped*/
 
168
    char *document_root = NULL;         /* Corrected value of DOCUMENT_ROOT  */
 
169
    char *path_info = NULL;             /* PATH_INFO extracted from pgm      */
 
170
    char *pgm_buff = NULL;              /* PATH_INFO extraction buffer       */
 
171
    char *path_translated;              /* From document_root/path_info      */
 
172
 
 
173
    if (isEmpty(arg) || strlen(arg) <= 8) {
 
174
        HTAlert(BAD_REQUEST);
 
175
        status = -2;
 
176
        return(status);
 
177
 
 
178
    } else {
 
179
        if (strncmp(arg, "lynxcgi://localhost", 19) == 0) {
 
180
            StrAllocCopy(pgm, arg+19);
 
181
        } else {
 
182
            StrAllocCopy(pgm, arg+8);
 
183
        }
 
184
        if ((cp=strchr(pgm, '?')) != NULL) { /* Need to terminate executable */
 
185
            *cp++ = '\0';
 
186
            pgm_args = cp;
 
187
        }
 
188
    }
 
189
 
 
190
    StrAllocCopy(orig_pgm, pgm);
 
191
    if ((cp = trimPoundSelector(pgm)) != NULL) {
 
192
        /*
 
193
         *  Strip a #fragment from path.  In this case any pgm_args
 
194
         *  found above will also be bogus, since the '?' came after
 
195
         *  the '#' and is part of the fragment.  Note that we don't
 
196
         *  handle the case where a '#' appears after a '?' properly
 
197
         *  according to URL rules. - kw
 
198
         */
 
199
        pgm_args = NULL;
 
200
    }
 
201
    HTUnEscape(pgm);
 
202
 
 
203
    /* BEGIN WebSter Mods */
 
204
    /* If pgm is not stat-able, see if PATH_INFO data is at the end of pgm */
 
205
    if ((statrv = stat(pgm, &stat_buf)) < 0) {
 
206
        StrAllocCopy(pgm_buff, pgm);
 
207
        while (statrv < 0 || (statrv = stat(pgm_buff, &stat_buf)) < 0) {
 
208
            if ((cp=strrchr(pgm_buff, '/')) != NULL) {
 
209
                *cp = '\0';
 
210
                statrv = 1;     /* force new stat()  - kw */
 
211
            } else {
 
212
                PERROR("strrchr(pgm_buff, '/') returned NULL");
 
213
                break;
 
214
            }
 
215
        }
 
216
 
 
217
        if (statrv < 0) {
 
218
            /* Did not find PATH_INFO data */
 
219
            PERROR("stat() of pgm_buff failed");
 
220
        } else {
 
221
            /* Found PATH_INFO data.  Strip it off of pgm and into path_info. */
 
222
            StrAllocCopy(path_info, pgm + strlen(pgm_buff));
 
223
            /* The following is safe since pgm_buff was derived from pgm
 
224
               by stripping stuff off its end and by HTUnEscaping, so we
 
225
               know we have enough memory allocated for pgm.  Note that
 
226
               pgm_args may still point into that memory, so we cannot
 
227
               reallocate pgm here. - kw */
 
228
            strcpy(pgm, pgm_buff);
 
229
            CTRACE((tfp, "LYNXCGI: stat() of %s succeeded, path_info=\"%s\".\n",
 
230
                        pgm_buff, path_info));
 
231
        }
 
232
        FREE(pgm_buff);
 
233
    }
 
234
    /* END WebSter Mods */
 
235
 
 
236
    if (statrv != 0) {
 
237
        /*
 
238
         *  Neither the path as given nor any components examined by
 
239
         *  backing up were stat()able. - kw
 
240
         */
 
241
        HTAlert(gettext("Unable to access cgi script"));
 
242
        PERROR("stat() failed");
 
243
        status = -4;
 
244
 
 
245
    } else
 
246
#ifdef _WINDOWS /* 1998/01/14 (Wed) 09:16:04 */
 
247
#define isExecutable(mode) (mode & (S_IXUSR))
 
248
#else
 
249
#define isExecutable(mode) (mode & (S_IXUSR|S_IXGRP|S_IXOTH))
 
250
#endif
 
251
    if (!(S_ISREG(stat_buf.st_mode) && isExecutable(stat_buf.st_mode))) {
 
252
        /*
 
253
         *  Not a runnable file, See if we can load it using "file:" code.
 
254
         */
 
255
        char *new_arg = NULL;
 
256
 
 
257
        /*
 
258
         *  But try "file:" only if the file we are looking at is the path
 
259
         *  as given (no path_info was extracted), otherwise it will be
 
260
         *  to confusing to know just what file is loaded. - kw
 
261
         */
 
262
        if (path_info) {
 
263
            CTRACE((tfp, "%s is not a file and %s not an executable, giving up.\n",
 
264
                        orig_pgm, pgm));
 
265
            FREE(path_info);
 
266
            FREE(pgm);
 
267
            FREE(orig_pgm);
 
268
            status = -4;
 
269
            return(status);
 
270
        }
 
271
 
 
272
        LYLocalFileToURL (&new_arg, orig_pgm);
 
273
 
 
274
        CTRACE((tfp, "%s is not an executable file, passing the buck.\n", arg));
 
275
        status = HTLoadFile(new_arg, anAnchor, format_out, sink);
 
276
        FREE(new_arg);
 
277
 
 
278
    } else if (path_info &&
 
279
               anAnchor != HTMainAnchor &&
 
280
               !(reloading && anAnchor->document) &&
 
281
               strcmp(arg, HTLoadedDocumentURL()) &&
 
282
               HText_AreDifferent(anAnchor, arg) &&
 
283
               HTUnEscape(orig_pgm) &&
 
284
               !exec_ok(HTLoadedDocumentURL(), orig_pgm,
 
285
                        CGI_PATH)) { /* exec_ok gives out msg. */
 
286
        /*
 
287
         *  If we have extra path info and are not just reloading
 
288
         *  the current, check the full file path (after unescaping)
 
289
         *  now to catch forbidden segments. - kw
 
290
         */
 
291
        status = HT_NOT_LOADED;
 
292
 
 
293
    } else if (no_lynxcgi) {
 
294
        HTUserMsg(CGI_DISABLED);
 
295
        status = HT_NOT_LOADED;
 
296
 
 
297
    } else if (no_bookmark_exec &&
 
298
               anAnchor != HTMainAnchor &&
 
299
               !(reloading && anAnchor->document) &&
 
300
               strcmp(arg, HTLoadedDocumentURL()) &&
 
301
               HText_AreDifferent(anAnchor, arg) &&
 
302
               HTLoadedDocumentBookmark()) {
 
303
        /*
 
304
         *  If we are reloading a lynxcgi document that had already been
 
305
         *  loaded, the various checks above should allow it even if
 
306
         *  no_bookmark_exec is TRUE an we are not now coming from a
 
307
         *  bookmark page. - kw
 
308
         */
 
309
        HTUserMsg(BOOKMARK_EXEC_DISABLED);
 
310
        status = HT_NOT_LOADED;
 
311
 
 
312
    } else if (anAnchor != HTMainAnchor &&
 
313
               !(reloading && anAnchor->document) &&
 
314
               strcmp(arg, HTLoadedDocumentURL()) &&
 
315
               HText_AreDifferent(anAnchor, arg) &&
 
316
               !exec_ok(HTLoadedDocumentURL(), pgm,
 
317
                        CGI_PATH)) { /* exec_ok gives out msg. */
 
318
        /*
 
319
         *  If we are reloading a lynxcgi document that had already been
 
320
         *  loaded, the various checks above should allow it even if
 
321
         *  exec_ok() would reject it because we are not now coming from
 
322
         *  a document with a URL allowed by TRUSTED_LYNXCGI rules. - kw
 
323
         */
 
324
        status = HT_NOT_LOADED;
 
325
 
 
326
    } else {
 
327
        HTFormat format_in;
 
328
        HTStream *target  = NULL;               /* Unconverted data */
 
329
        int fd1[2], fd2[2];
 
330
        char buf[1024];
 
331
        int pid;
 
332
#ifdef HAVE_TYPE_UNIONWAIT
 
333
        union wait wstatus;
 
334
#else
 
335
        int wstatus;
 
336
#endif
 
337
 
 
338
        if (anAnchor->isHEAD || keep_mime_headers) {
 
339
 
 
340
            /* Show output as plain text */
 
341
            format_in = WWW_PLAINTEXT;
 
342
        } else {
 
343
 
 
344
            /* Decode full HTTP response */
 
345
            format_in = HTAtom_for("www/mime");
 
346
        }
 
347
 
 
348
        target = HTStreamStack(format_in,
 
349
                               format_out,
 
350
                               sink, anAnchor);
 
351
 
 
352
        if (!target || target == NULL) {
 
353
            char *tmp = 0;
 
354
            HTSprintf0(&tmp, CANNOT_CONVERT_I_TO_O,
 
355
                       HTAtom_name(format_in),
 
356
                       HTAtom_name(format_out));
 
357
            HTAlert(tmp);
 
358
            FREE(tmp);
 
359
            status = HT_NOT_LOADED;
 
360
 
 
361
        } else if (anAnchor->post_data && pipe(fd1) < 0) {
 
362
            HTAlert(CONNECT_SET_FAILED);
 
363
            PERROR("pipe() failed");
 
364
            status = -3;
 
365
 
 
366
        } else if (pipe(fd2) < 0) {
 
367
            HTAlert(CONNECT_SET_FAILED);
 
368
            PERROR("pipe() failed");
 
369
            close(fd1[0]);
 
370
            close(fd1[1]);
 
371
            status = -3;
 
372
 
 
373
        } else {
 
374
            static BOOL first_time = TRUE;      /* One time setup flag */
 
375
 
 
376
            if (first_time) {   /* Set up static environment variables */
 
377
                first_time = FALSE;     /* Only once */
 
378
 
 
379
                add_environment_value("REMOTE_HOST=localhost");
 
380
                add_environment_value("REMOTE_ADDR=127.0.0.1");
 
381
 
 
382
                HTSprintf0(&user_agent, "HTTP_USER_AGENT=%s/%s libwww/%s",
 
383
                        LYNX_NAME, LYNX_VERSION, HTLibraryVersion);
 
384
                add_environment_value(user_agent);
 
385
 
 
386
                HTSprintf0(&server_software, "SERVER_SOFTWARE=%s/%s",
 
387
                        LYNX_NAME, LYNX_VERSION);
 
388
                add_environment_value(server_software);
 
389
            }
 
390
            fflush(stdout);
 
391
            fflush(stderr);
 
392
            CTRACE_FLUSH(tfp);
 
393
 
 
394
            if ((pid = fork()) > 0) { /* The good, */
 
395
                int chars, total_chars;
 
396
 
 
397
                close(fd2[1]);
 
398
 
 
399
                if (anAnchor->post_data) {
 
400
                    int written, remaining, total_written = 0;
 
401
 
 
402
                    close(fd1[0]);
 
403
 
 
404
                    /* We have form data to push across the pipe */
 
405
                    if (TRACE) {
 
406
                        CTRACE((tfp, "LYNXCGI: Doing post, content-type '%s'\n",
 
407
                                anAnchor->post_content_type));
 
408
                        CTRACE((tfp, "LYNXCGI: Writing:\n"));
 
409
                        trace_bstring(anAnchor->post_data);
 
410
                        CTRACE((tfp, "----------------------------------\n"));
 
411
                    }
 
412
                    remaining = BStrLen(anAnchor->post_data);
 
413
                    while ((written = write(fd1[1],
 
414
                                            BStrData(anAnchor->post_data) + total_written,
 
415
                                            remaining)) != 0) {
 
416
                        if (written < 0) {
 
417
#ifdef EINTR
 
418
                            if (errno == EINTR)
 
419
                                continue;
 
420
#endif /* EINTR */
 
421
#ifdef ERESTARTSYS
 
422
                            if (errno == ERESTARTSYS)
 
423
                                continue;
 
424
#endif /* ERESTARTSYS */
 
425
                            PERROR("write() of POST data failed");
 
426
                            break;
 
427
                        }
 
428
                        CTRACE((tfp, "LYNXCGI: Wrote %d bytes of POST data.\n",
 
429
                                    written));
 
430
                        total_written += written;
 
431
                        remaining -= written;
 
432
                        if (remaining == 0)
 
433
                            break;
 
434
                    }
 
435
                    if (remaining != 0) {
 
436
                        CTRACE((tfp, "LYNXCGI: %d bytes remain unwritten!\n",
 
437
                                    remaining));
 
438
                    }
 
439
                    close(fd1[1]);
 
440
                }
 
441
 
 
442
                HTReadProgress(total_chars = 0, 0);
 
443
                while((chars = read(fd2[0], buf, sizeof(buf))) != 0) {
 
444
                    if (chars < 0) {
 
445
#ifdef EINTR
 
446
                        if (errno == EINTR)
 
447
                            continue;
 
448
#endif /* EINTR */
 
449
#ifdef ERESTARTSYS
 
450
                        if (errno == ERESTARTSYS)
 
451
                            continue;
 
452
#endif /* ERESTARTSYS */
 
453
                        PERROR("read() of CGI output failed");
 
454
                        break;
 
455
                    }
 
456
                    HTReadProgress(total_chars += chars, 0);
 
457
                    CTRACE((tfp, "LYNXCGI: Rx: %.*s\n", chars, buf));
 
458
                    (*target->isa->put_block)(target, buf, chars);
 
459
                }
 
460
 
 
461
                if (chars < 0 && total_chars == 0) {
 
462
                    status = HT_NOT_LOADED;
 
463
                    (*target->isa->_abort)(target, NULL);
 
464
                    target = NULL;
 
465
                } else if (chars != 0) {
 
466
                    status = HT_PARTIAL_CONTENT;
 
467
                } else {
 
468
                    status = HT_LOADED;
 
469
                }
 
470
 
 
471
#if !HAVE_WAITPID
 
472
                while (wait(&wstatus) != pid)
 
473
                    ; /* do nothing */
 
474
#else
 
475
                while (-1 == waitpid(pid, &wstatus, 0)) { /* wait for child */
 
476
#ifdef EINTR
 
477
                    if (errno == EINTR)
 
478
                        continue;
 
479
#endif /* EINTR */
 
480
#ifdef ERESTARTSYS
 
481
                    if (errno == ERESTARTSYS)
 
482
                        continue;
 
483
#endif /* ERESTARTSYS */
 
484
                    break;
 
485
                }
 
486
#endif /* !HAVE_WAITPID */
 
487
                close(fd2[0]);
 
488
 
 
489
            } else if (pid == 0) { /* The Bad, */
 
490
                char **argv = NULL;
 
491
                int argv_cnt = 3; /* name, one arg and terminator */
 
492
                char **cur_argv = NULL;
 
493
                int exec_errno;
 
494
 
 
495
                /* Set up output pipe */
 
496
                close(fd2[0]);
 
497
                dup2(fd2[1], fileno(stdout)); /* Should check success code */
 
498
                dup2(fd2[1], fileno(stderr));
 
499
                close(fd2[1]);
 
500
 
 
501
                if (language && *language) {
 
502
                HTSprintf0(&accept_language, "HTTP_ACCEPT_LANGUAGE=%s", language);
 
503
                add_environment_value(accept_language);
 
504
                }
 
505
 
 
506
                if (pref_charset && *pref_charset) {
 
507
                    cp = NULL;
 
508
                    StrAllocCopy(cp, "HTTP_ACCEPT_CHARSET=");
 
509
                    StrAllocCat(cp, pref_charset);
 
510
                    add_environment_value(cp);
 
511
                }
 
512
 
 
513
                if (anAnchor->post_data &&
 
514
                    anAnchor->post_content_type) {
 
515
                    cp = NULL;
 
516
                    StrAllocCopy(cp, "CONTENT_TYPE=");
 
517
                    StrAllocCat(cp, anAnchor->post_content_type);
 
518
                    add_environment_value(cp);
 
519
                }
 
520
 
 
521
                if (anAnchor->post_data) { /* post script, read stdin */
 
522
                    close(fd1[1]);
 
523
                    dup2(fd1[0], fileno(stdin));
 
524
                    close(fd1[0]);
 
525
 
 
526
                    /* Build environment variables */
 
527
 
 
528
                    add_environment_value("REQUEST_METHOD=POST");
 
529
 
 
530
                    HTSprintf0(&post_len, "CONTENT_LENGTH=%d",
 
531
                               BStrLen(anAnchor->post_data));
 
532
                    add_environment_value(post_len);
 
533
                } else {
 
534
                    close(fileno(stdin));
 
535
 
 
536
                    if (anAnchor->isHEAD) {
 
537
                        add_environment_value("REQUEST_METHOD=HEAD");
 
538
                    }
 
539
                }
 
540
 
 
541
                /*
 
542
                 * Set up argument line, mainly for <index> scripts
 
543
                 */
 
544
                if (pgm_args != NULL) {
 
545
                    for (cp = pgm_args; *cp != '\0'; cp++) {
 
546
                        if (*cp == '+') {
 
547
                            argv_cnt++;
 
548
                        }
 
549
                    }
 
550
                }
 
551
 
 
552
                argv = (char**)malloc(argv_cnt * sizeof(char*));
 
553
                if (argv == NULL) {
 
554
                    outofmem(__FILE__, "LYCgi");
 
555
                }
 
556
                cur_argv = argv + 1;            /* For argv[0] */
 
557
                if (pgm_args != NULL) {
 
558
                    char *cr;
 
559
 
 
560
                    /* Data for a get/search form */
 
561
                    if (is_www_index) {
 
562
                        add_environment_value("REQUEST_METHOD=SEARCH");
 
563
                    } else if (!anAnchor->isHEAD && !anAnchor->post_data) {
 
564
                        add_environment_value("REQUEST_METHOD=GET");
 
565
                    }
 
566
 
 
567
                    cp = NULL;
 
568
                    StrAllocCopy(cp, "QUERY_STRING=");
 
569
                    StrAllocCat(cp, pgm_args);
 
570
                    add_environment_value(cp);
 
571
 
 
572
                    /*
 
573
                     * Split up arguments into argv array
 
574
                     */
 
575
                    cp = pgm_args;
 
576
                    cr = cp;
 
577
                    while(1) {
 
578
                        if (*cp == '\0') {
 
579
                            *(cur_argv++) = HTUnEscape(cr);
 
580
                            break;
 
581
 
 
582
                        } else if (*cp == '+') {
 
583
                            *cp++ = '\0';
 
584
                            *(cur_argv++) = HTUnEscape(cr);
 
585
                            cr = cp;
 
586
                        }
 
587
                        cp++;
 
588
                    }
 
589
                } else if (!anAnchor->isHEAD && !anAnchor->post_data) {
 
590
                    add_environment_value("REQUEST_METHOD=GET");
 
591
                }
 
592
                *cur_argv = NULL;       /* Terminate argv */
 
593
                argv[0] = pgm;
 
594
 
 
595
                /* Begin WebSter Mods  -jkt */
 
596
                if (LYCgiDocumentRoot != NULL) {
 
597
                    /* Add DOCUMENT_ROOT to env */
 
598
                    cp = NULL;
 
599
                    StrAllocCopy(cp, "DOCUMENT_ROOT=");
 
600
                    StrAllocCat(cp, LYCgiDocumentRoot);
 
601
                    add_environment_value(cp);
 
602
                }
 
603
                if (path_info != NULL ) {
 
604
                    /* Add PATH_INFO to env */
 
605
                    cp = NULL;
 
606
                    StrAllocCopy(cp, "PATH_INFO=");
 
607
                    StrAllocCat(cp, path_info);
 
608
                    add_environment_value(cp);
 
609
                }
 
610
                if (LYCgiDocumentRoot != NULL && path_info != NULL ) {
 
611
                    /* Construct and add PATH_TRANSLATED to env */
 
612
                    StrAllocCopy(document_root, LYCgiDocumentRoot);
 
613
                    LYTrimHtmlSep(document_root);
 
614
                    path_translated = document_root;
 
615
                    StrAllocCat(path_translated, path_info);
 
616
                    cp = NULL;
 
617
                    StrAllocCopy(cp, "PATH_TRANSLATED=");
 
618
                    StrAllocCat(cp, path_translated);
 
619
                    add_environment_value(cp);
 
620
                    FREE(path_translated);
 
621
                }
 
622
                /* End WebSter Mods  -jkt */
 
623
 
 
624
                execve(argv[0], argv, env);
 
625
                exec_errno = errno;
 
626
                PERROR("execve failed");
 
627
                printf("Content-Type: text/plain\r\n\r\n");
 
628
                if (!anAnchor->isHEAD) {
 
629
                    printf("exec of %s failed", pgm);
 
630
                    printf(": %s.\r\n", LYStrerror(exec_errno));
 
631
                }
 
632
                fflush(stdout);
 
633
                fflush(stderr);
 
634
                _exit(1);
 
635
 
 
636
            } else {    /* and the Ugly */
 
637
                HTAlert(CONNECT_FAILED);
 
638
                PERROR("fork() failed");
 
639
                status = HT_NO_DATA;
 
640
                close(fd1[0]);
 
641
                close(fd1[1]);
 
642
                close(fd2[0]);
 
643
                close(fd2[1]);
 
644
                status = -1;
 
645
            }
 
646
 
 
647
        }
 
648
        if (target != NULL) {
 
649
            (*target->isa->_free)(target);
 
650
        }
 
651
    }
 
652
    FREE(path_info);
 
653
    FREE(pgm);
 
654
    FREE(orig_pgm);
 
655
#else  /* VMS */
 
656
    HTStream *target;
 
657
    char *buf = 0;
 
658
 
 
659
    target = HTStreamStack(WWW_HTML,
 
660
                           format_out,
 
661
                           sink, anAnchor);
 
662
 
 
663
    HTSprintf0(&buf, "<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n",
 
664
               gettext("Good Advice"));
 
665
    (*target->isa->put_block)(target, buf, strlen(buf));
 
666
 
 
667
    HTSprintf0(&buf, "<h1>%s</h1>\n", gettext("Good Advice"));
 
668
    (*target->isa->put_block)(target, buf, strlen(buf));
 
669
 
 
670
    HTSprintf0(&buf, "%s <a\n", gettext("An excellent http server for VMS is available via"));
 
671
    (*target->isa->put_block)(target, buf, strlen(buf));
 
672
 
 
673
    HTSprintf0(&buf,
 
674
               "href=\"http://kcgl1.eng.ohio-state.edu/www/doc/serverinfo.html\"\n");
 
675
    (*target->isa->put_block)(target, buf, strlen(buf));
 
676
 
 
677
    HTSprintf0(&buf, ">%s</a>.\n", gettext("this link"));
 
678
    (*target->isa->put_block)(target, buf, strlen(buf));
 
679
 
 
680
    HTSprintf0(&buf, "<p>%s\n",
 
681
               gettext("It provides state of the art CGI script support.\n"));
 
682
    (*target->isa->put_block)(target, buf, strlen(buf));
 
683
 
 
684
    HTSprintf0(&buf,"</body>\n</html>\n");
 
685
    (*target->isa->put_block)(target, buf, strlen(buf));
 
686
 
 
687
    (*target->isa->_free)(target);
 
688
    FREE(buf);
 
689
    status = HT_LOADED;
 
690
#endif /* VMS */
 
691
#else /* LYNXCGI_LINKS */
 
692
    HTUserMsg(CGI_NOT_COMPILED);
 
693
    status = HT_NOT_LOADED;
 
694
#endif /* LYNXCGI_LINKS */
 
695
    return(status);
 
696
}
 
697
#endif /* __MINGW32__ */
 
698
 
 
699
#ifdef GLOBALDEF_IS_MACRO
 
700
#define _LYCGI_C_GLOBALDEF_1_INIT { "lynxcgi", LYLoadCGI, 0 }
 
701
GLOBALDEF (HTProtocol,LYLynxCGI,_LYCGI_C_GLOBALDEF_1_INIT);
 
702
#else
 
703
GLOBALDEF PUBLIC HTProtocol LYLynxCGI = { "lynxcgi", LYLoadCGI, 0 };
 
704
#endif /* GLOBALDEF_IS_MACRO */