~ubuntu-branches/ubuntu/precise/apparmor/precise-security

« back to all changes in this revision

Viewing changes to .pc/0009-apparmor-lp959560-part1.patch/parser/parser_misc.c

  • Committer: Package Import Robot
  • Author(s): Steve Beattie, Jamie Strandboge, Serge Hallyn, Steve Beattie
  • Date: 2012-04-12 06:17:42 UTC
  • Revision ID: package-import@ubuntu.com-20120412061742-9v75hjko2mjtbewv
Tags: 2.7.102-0ubuntu3
[ Jamie Strandboge ]
* debian/patches/0007-ubuntu-manpage-updates.patch: update apparmor(5)
  to describe Ubuntu's two-stage policy load and how to add utilize it
  when developing policy (LP: #974089)

[ Serge Hallyn ]
* debian/apparmor.init: do nothing in a container.  This can be
  removed once stacked profiles are supported and used by lxc.
  (LP: #978297)

[ Steve Beattie ]
* debian/patches/0008-apparmor-lp963756.patch: Fix permission mapping
  for change_profile onexec (LP: #963756)
* debian/patches/0009-apparmor-lp959560-part1.patch,
  debian/patches/0010-apparmor-lp959560-part2.patch: Update the parser
  to support the 'in' keyword for value lists, and make mount
  operations aware of 'in' keyword so they can affect the flags build
  list (LP: #959560)
* debian/patches/0011-apparmor-lp872446.patch: fix logprof missing
  exec events in complain mode (LP: #872446)
* debian/patches/0012-apparmor-lp978584.patch: allow inet6 access in
  dovecot imap-login profile (LP: #978584)
* debian/patches/0013-apparmor-lp800826.patch: fix libapparmor
  log parsing library from dropping apparmor network events that
  contain ip addresses or ports in them (LP: #800826)
* debian/patches/0014-apparmor-lp979095.patch: document new mount rule
  syntax and usage in apparmor.d(5) manpage (LP: #979095)
* debian/patches/0015-apparmor-lp963756.patch: Fix change_onexec
  for profiles without attachment specification (LP: #963756,
  LP: #978038)
* debian/patches/0016-apparmor-lp968956.patch: Fix protocol error when
  loading policy to kernels without compat patches (LP: #968956)
* debian/patches/0017-apparmor-lp979135.patch: Fix change_profile to
  grant access to /proc/attr api (LP: #979135)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
 
3
 *   NOVELL (All rights reserved)
 
4
 *
 
5
 *   This program is free software; you can redistribute it and/or
 
6
 *   modify it under the terms of version 2 of the GNU General Public
 
7
 *   License published by the Free Software Foundation.
 
8
 *
 
9
 *   This program is distributed in the hope that it will be useful,
 
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 *   GNU General Public License for more details.
 
13
 *
 
14
 *   You should have received a copy of the GNU General Public License
 
15
 *   along with this program; if not, contact Novell, Inc.
 
16
 */
 
17
 
 
18
/* assistance routines */
 
19
 
 
20
#include <assert.h>
 
21
#include <ctype.h>
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <stdarg.h>
 
25
#include <string.h>
 
26
#include <libintl.h>
 
27
#define _(s) gettext(s)
 
28
#include <netinet/in.h>
 
29
#include <linux/socket.h>
 
30
#include <linux/limits.h>
 
31
#include <arpa/inet.h>
 
32
#include <linux/capability.h>
 
33
#include <sys/types.h>
 
34
#include <sys/stat.h>
 
35
#include <fcntl.h>
 
36
#include <unistd.h>
 
37
 
 
38
#include "parser.h"
 
39
#include "parser_yacc.h"
 
40
#include "mount.h"
 
41
 
 
42
/* #define DEBUG */
 
43
#ifdef DEBUG
 
44
#undef PDEBUG
 
45
#define PDEBUG(fmt, args...) printf("Lexer: " fmt, ## args)
 
46
#else
 
47
#undef PDEBUG
 
48
#define PDEBUG(fmt, args...)    /* Do nothing */
 
49
#endif
 
50
#define NPDEBUG(fmt, args...)   /* Do nothing */
 
51
 
 
52
struct keyword_table {
 
53
        char *keyword;
 
54
        int token;
 
55
};
 
56
 
 
57
static struct keyword_table keyword_table[] = {
 
58
        /* network */
 
59
        {"network",             TOK_NETWORK},
 
60
        /* misc keywords */
 
61
        {"capability",          TOK_CAPABILITY},
 
62
        {"if",                  TOK_IF},
 
63
        {"else",                TOK_ELSE},
 
64
        {"not",                 TOK_NOT},
 
65
        {"defined",             TOK_DEFINED},
 
66
        {"change_profile",      TOK_CHANGE_PROFILE},
 
67
        {"unsafe",              TOK_UNSAFE},
 
68
        {"safe",                TOK_SAFE},
 
69
        {"link",                TOK_LINK},
 
70
        {"owner",               TOK_OWNER},
 
71
        {"user",                TOK_OWNER},
 
72
        {"other",               TOK_OTHER},
 
73
        {"subset",              TOK_SUBSET},
 
74
        {"audit",               TOK_AUDIT},
 
75
        {"deny",                TOK_DENY},
 
76
        {"set",                 TOK_SET},
 
77
        {"rlimit",              TOK_RLIMIT},
 
78
        {"alias",               TOK_ALIAS},
 
79
        {"rewrite",             TOK_ALIAS},
 
80
        {"ptrace",              TOK_PTRACE},
 
81
        {"file",                TOK_FILE},
 
82
        {"mount",               TOK_MOUNT},
 
83
        {"remount",             TOK_REMOUNT},
 
84
        {"umount",              TOK_UMOUNT},
 
85
        {"unmount",             TOK_UMOUNT},
 
86
        {"pivot_root",          TOK_PIVOTROOT},
 
87
        /* terminate */
 
88
        {NULL, 0}
 
89
};
 
90
 
 
91
static struct keyword_table rlimit_table[] = {
 
92
        {"cpu",                 RLIMIT_CPU},
 
93
        {"fsize",               RLIMIT_FSIZE},
 
94
        {"data",                RLIMIT_DATA},
 
95
        {"stack",               RLIMIT_STACK},
 
96
        {"core",                RLIMIT_CORE},
 
97
        {"rss",                 RLIMIT_RSS},
 
98
        {"nofile",              RLIMIT_NOFILE},
 
99
        {"ofile",               RLIMIT_OFILE},
 
100
        {"as",                  RLIMIT_AS},
 
101
        {"nproc",               RLIMIT_NPROC},
 
102
        {"memlock",             RLIMIT_MEMLOCK},
 
103
        {"locks",               RLIMIT_LOCKS},
 
104
        {"sigpending",          RLIMIT_SIGPENDING},
 
105
        {"msgqueue",            RLIMIT_MSGQUEUE},
 
106
#ifdef RLIMIT_NICE
 
107
        {"nice",                RLIMIT_NICE},
 
108
#endif
 
109
#ifdef RLIMIT_RTPRIO
 
110
        {"rtprio",              RLIMIT_RTPRIO},
 
111
#endif
 
112
        /* terminate */
 
113
        {NULL, 0}
 
114
};
 
115
 
 
116
/* for alpha matches, check for keywords */
 
117
static int get_table_token(const char *name __unused, struct keyword_table *table,
 
118
                           const char *keyword)
 
119
{
 
120
        int i;
 
121
 
 
122
        for (i = 0; table[i].keyword; i++) {
 
123
                PDEBUG("Checking %s %s\n", name, table[i].keyword);
 
124
                if (strcmp(keyword, table[i].keyword) == 0) {
 
125
                        PDEBUG("Found %s %s\n", name, table[i].keyword);
 
126
                        return table[i].token;
 
127
                }
 
128
        }
 
129
 
 
130
        PDEBUG("Unable to find %s %s\n", name, keyword);
 
131
        return -1;
 
132
}
 
133
 
 
134
static struct keyword_table capability_table[] = {
 
135
        /* capabilities */
 
136
        #include "cap_names.h"
 
137
#ifndef CAP_SYSLOG
 
138
        {"syslog", 34},
 
139
#endif
 
140
        /* terminate */
 
141
        {NULL, 0}
 
142
};
 
143
 
 
144
/* for alpha matches, check for keywords */
 
145
int get_keyword_token(const char *keyword)
 
146
{
 
147
        return get_table_token("keyword", keyword_table, keyword);
 
148
}
 
149
 
 
150
int name_to_capability(const char *keyword)
 
151
{
 
152
        return get_table_token("capability", capability_table, keyword);
 
153
}
 
154
 
 
155
int get_rlimit(const char *name)
 
156
{
 
157
        return get_table_token("rlimit", rlimit_table, name);
 
158
}
 
159
 
 
160
struct network_tuple {
 
161
        char *family_name;
 
162
        unsigned int family;
 
163
        char *type_name;
 
164
        unsigned int type;
 
165
        char *protocol_name;
 
166
        unsigned int protocol;
 
167
};
 
168
 
 
169
/* FIXME: currently just treating as a bit mask this will have to change
 
170
 * set up a table of mappings, there can be several mappings for a
 
171
 * given match.
 
172
 * currently the mapping does not set the protocol for stream/dgram to
 
173
 * anything other than 0.
 
174
 *   network inet tcp -> network inet stream 0 instead of
 
175
 *   network inet raw tcp.
 
176
 * some entries are just provided for completeness at this time
 
177
 */
 
178
/* values stolen from /etc/protocols - needs to change */
 
179
#define RAW_TCP 6
 
180
#define RAW_UDP 17
 
181
#define RAW_ICMP 1
 
182
#define RAW_ICMPv6 58
 
183
 
 
184
/* used by af_name.h to auto generate table entries for "name", AF_NAME
 
185
 * pair */
 
186
#define AA_GEN_NET_ENT(name, AF) {name, AF, "stream", SOCK_STREAM, "", 0xffffff}, {name, AF, "dgram", SOCK_DGRAM, "", 0xffffff}, {name, AF, "seqpacket", SOCK_SEQPACKET, "", 0xffffff}, {name, AF, "rdm", SOCK_RDM, "", 0xffffff}, {name, AF, "raw", SOCK_RAW, "", 0xffffff}, {name, AF, "packet", SOCK_PACKET, "", 0xffffff},
 
187
/*FIXME: missing {name, AF, "dccp", SOCK_DCCP, "", 0xfffffff}, */
 
188
 
 
189
static struct network_tuple network_mappings[] = {
 
190
        /* basic types */
 
191
        #include "af_names.h"
 
192
/* FIXME: af_names.h is missing AF_LLC, AF_TIPC */
 
193
        /* mapped types */
 
194
        {"inet",        AF_INET,        "raw",          SOCK_RAW,
 
195
         "tcp",         1 << RAW_TCP},
 
196
        {"inet",        AF_INET,        "raw",          SOCK_RAW,
 
197
         "udp",         1 << RAW_UDP},
 
198
        {"inet",        AF_INET,        "raw",          SOCK_RAW,
 
199
         "icmp",        1 << RAW_ICMP},
 
200
        {"inet",        AF_INET,        "tcp",          SOCK_STREAM,
 
201
         "",            0xffffffff},    /* should we give raw tcp too? */
 
202
        {"inet",        AF_INET,        "udp",          SOCK_DGRAM,
 
203
         "",            0xffffffff},    /* should these be open masks? */
 
204
        {"inet",        AF_INET,        "icmp",         SOCK_RAW,
 
205
         "",            1 << RAW_ICMP},
 
206
        {"inet6",       AF_INET6,       "tcp",          SOCK_STREAM,
 
207
         "",            0xffffffff},
 
208
        {"inet6",       AF_INET6,       "udp",          SOCK_DGRAM,
 
209
         "",            0xffffffff},
 
210
/* what do we do with icmp on inet6?
 
211
        {"inet6",       AF_INET,        "icmp",         SOCK_RAW,       0},
 
212
        {"inet6",       AF_INET,        "icmpv6",       SOCK_RAW,       0},
 
213
*/
 
214
        /* terminate */
 
215
        {NULL, 0, NULL, 0, NULL, 0}
 
216
};
 
217
 
 
218
/* The apparmor kernel patches up until 2.6.38 didn't handle networking
 
219
 * tables with sizes > AF_MAX correctly.  This could happen when the
 
220
 * parser was built against newer kernel headers and then used to load
 
221
 * policy on an older kernel.  This could happen during upgrades or
 
222
 * in multi-kernel boot systems.
 
223
 *
 
224
 * Try to detect the running kernel version and use that to determine
 
225
 * AF_MAX
 
226
 */
 
227
#define PROC_VERSION "/proc/sys/kernel/osrelease"
 
228
static size_t kernel_af_max(void) {
 
229
        char buffer[32];
 
230
        int major;
 
231
        int fd, res;
 
232
 
 
233
        if (!net_af_max_override) {
 
234
                return 0;
 
235
        }
 
236
        /* the override parameter is specifying the max value */
 
237
        if (net_af_max_override > 0)
 
238
                return net_af_max_override;
 
239
 
 
240
        fd = open(PROC_VERSION, O_RDONLY);
 
241
        if (!fd)
 
242
                /* fall back to default provided during build */
 
243
                return 0;
 
244
        res = read(fd, &buffer, sizeof(buffer));
 
245
        close(fd);
 
246
        if (!res)
 
247
                return 0;
 
248
        buffer[sizeof(buffer)-1] = '\0';
 
249
        res = sscanf(buffer, "2.6.%d", &major);
 
250
        if (res != 1)
 
251
                return 0;
 
252
 
 
253
        switch(major) {
 
254
        case 24:
 
255
        case 25:
 
256
        case 26:
 
257
                return 34;
 
258
        case 27:
 
259
                return 35;
 
260
        case 28:
 
261
        case 29:
 
262
        case 30:
 
263
                return 36;
 
264
        case 31:
 
265
        case 32:
 
266
        case 33:
 
267
        case 34:
 
268
        case 35:
 
269
                return 37;
 
270
        case 36:
 
271
        case 37:
 
272
                return 38;
 
273
        /* kernels .38 and later should handle this correctly so no
 
274
         * static mapping needed
 
275
         */
 
276
        default:
 
277
                return 0;
 
278
        }
 
279
}
 
280
 
 
281
/* Yuck. We grab AF_* values to define above from linux/socket.h because
 
282
 * they are more accurate than sys/socket.h for what the kernel actually
 
283
 * supports. However, we can't just include linux/socket.h directly,
 
284
 * because the AF_* definitions are protected with an ifdef KERNEL
 
285
 * wrapper, but we don't want to define that because that can cause
 
286
 * other redefinitions from glibc. However, because the kernel may have
 
287
 * more definitions than glibc, we need make sure AF_MAX reflects this,
 
288
 * hence the wrapping function.
 
289
 */
 
290
size_t get_af_max() {
 
291
        size_t af_max;
 
292
        /* HACK: declare that version without "create" had a static AF_MAX */
 
293
        if (!perms_create && !net_af_max_override)
 
294
                net_af_max_override = -1;
 
295
 
 
296
#if AA_AF_MAX > AF_MAX
 
297
        af_max = AA_AF_MAX;
 
298
#else
 
299
        af_max = AF_MAX;
 
300
#endif
 
301
 
 
302
        /* HACK: some kernels didn't handle network tables from parsers
 
303
         * compiled against newer kernel headers as they are larger than
 
304
         * the running kernel expected.  If net_override is defined check
 
305
         * to see if there is a static max specified for that kernel
 
306
         */
 
307
        if (net_af_max_override) {
 
308
                size_t max = kernel_af_max();
 
309
                if (max && max < af_max)
 
310
                        return max;
 
311
        }
 
312
 
 
313
        return af_max;
 
314
}
 
315
struct aa_network_entry *new_network_ent(unsigned int family,
 
316
                                         unsigned int type,
 
317
                                         unsigned int protocol)
 
318
{
 
319
        struct aa_network_entry *new_entry;
 
320
        new_entry = calloc(1, sizeof(struct aa_network_entry));
 
321
        if (new_entry) {
 
322
                new_entry->family = family;
 
323
                new_entry->type = type;
 
324
                new_entry->protocol = protocol;
 
325
                new_entry->next = NULL;
 
326
        }
 
327
        return new_entry;
 
328
}
 
329
 
 
330
struct aa_network_entry *network_entry(const char *family, const char *type,
 
331
                                       const char *protocol)
 
332
{
 
333
        int i;
 
334
        struct aa_network_entry *new_entry, *entry = NULL;
 
335
 
 
336
        for (i = 0; network_mappings[i].family_name; i++) {
 
337
                if (family) {
 
338
                        PDEBUG("Checking family %s\n", network_mappings[i].family_name);
 
339
                        if (strcmp(family, network_mappings[i].family_name) != 0)
 
340
                                continue;
 
341
                        PDEBUG("Found family %s\n", family);
 
342
                }
 
343
                if (type) {
 
344
                        PDEBUG("Checking type %s\n", network_mappings[i].type_name);
 
345
                        if (strcmp(type, network_mappings[i].type_name) != 0)
 
346
                                continue;
 
347
                        PDEBUG("Found type %s\n", type);
 
348
                }
 
349
                if (protocol) {
 
350
                        PDEBUG("Checking protocol type %s\n", network_mappings[i].protocol_name);
 
351
                        if (strcmp(type, network_mappings[i].protocol_name) != 0)
 
352
                                continue;
 
353
                        /* fixme should we allow specifying protocol by #
 
354
                         * without needing the protocol mapping? */
 
355
                }
 
356
                /* if here we have a match */
 
357
                new_entry = new_network_ent(network_mappings[i].family,
 
358
                                            network_mappings[i].type,
 
359
                                            network_mappings[i].protocol);
 
360
                if (!new_entry)
 
361
                        yyerror(_("Memory allocation error."));
 
362
                new_entry->next = entry;
 
363
                entry = new_entry;
 
364
        }
 
365
 
 
366
        return entry;
 
367
};
 
368
 
 
369
char *processunquoted(char *string, int len)
 
370
{
 
371
        char *tmp, *s;
 
372
        int l;
 
373
 
 
374
        tmp = (char *)malloc(len + 1);
 
375
        if (!tmp)
 
376
                return NULL;
 
377
 
 
378
        s = tmp;
 
379
        for (l = 0; l < len; l++) {
 
380
                if (string[l] == '\\' && l < len - 3) {
 
381
                        if (strchr("0123", string[l + 1]) &&
 
382
                            strchr("0123456789", string[l + 2]) &&
 
383
                            strchr("0123456789", string[l + 3])) {
 
384
                                /* three digit octal */
 
385
                                int res = (string[l + 1] - '0') * 64 +
 
386
                                          (string[l + 2] - '0') * 8 +
 
387
                                          (string[l + 3] - '0');
 
388
                                *s = res;
 
389
                                l += 3;
 
390
                        } else {
 
391
                                *s = string[l];
 
392
                        }
 
393
                        s++;
 
394
                } else {
 
395
                        *s = string[l];
 
396
                        s++;
 
397
                }
 
398
        }
 
399
 
 
400
        *s = 0;
 
401
 
 
402
        return tmp;
 
403
}
 
404
 
 
405
char *processid(char *string, int len)
 
406
{
 
407
        /* lexer should never call this fn if len <= 0 */
 
408
        assert(len > 0);
 
409
 
 
410
        if (*string == '"')
 
411
                return processquoted(string, len);
 
412
        return processunquoted(string, len);
 
413
}
 
414
 
 
415
/* rewrite a quoted string substituting escaped characters for the
 
416
 * real thing.  Strip the quotes around the string */
 
417
 
 
418
char *processquoted(char *string, int len)
 
419
{
 
420
        char *tmp, *s;
 
421
        int l;
 
422
        /* the result string will be shorter or equal in length */
 
423
        tmp = (char *)malloc(len + 1);
 
424
        if (!tmp)
 
425
                return NULL;
 
426
 
 
427
        s = tmp;
 
428
        for (l = 1; l < len - 1; l++) {
 
429
                if (string[l] == '\\' && l < len - 2) {
 
430
                        switch (string[l + 1]) {
 
431
                        case 't':
 
432
                                *s = '\t';
 
433
                                l++;
 
434
                                break;
 
435
                        case 'n':
 
436
                                *s = '\n';
 
437
                                l++;
 
438
                                break;
 
439
                        case 'r':
 
440
                                *s = '\r';
 
441
                                l++;
 
442
                                break;
 
443
                        case '"':
 
444
                                *s = '"';
 
445
                                l++;
 
446
                                break;
 
447
                        case '\\':
 
448
                                *s = '\\';
 
449
                                l++;
 
450
                                break;
 
451
                        case '0': case '1': case '2': case '3':
 
452
                                if ((l < len - 4) &&
 
453
                                    strchr("0123456789", string[l + 2]) &&
 
454
                                    strchr("0123456789", string[l + 3])) {
 
455
                                        /* three digit octal */
 
456
                                        int res = (string[l + 1] - '0') * 64 +
 
457
                                            (string[l + 2] - '0') * 8 +
 
458
                                            (string[l + 3] - '0');
 
459
                                        *s = res;
 
460
                                        l += 3;
 
461
                                        break;
 
462
                                }
 
463
                                /* fall through */
 
464
                        default:
 
465
                                /* any unsupported escape sequence results in all
 
466
                                   chars being copied. */
 
467
                                *s = string[l];
 
468
                        }
 
469
                        s++;
 
470
                } else {
 
471
                        *s = string[l];
 
472
                        s++;
 
473
                }
 
474
        }
 
475
 
 
476
        *s = 0;
 
477
 
 
478
        return tmp;
 
479
}
 
480
 
 
481
/* strip off surrounding delimiters around variables */
 
482
char *process_var(const char *var)
 
483
{
 
484
        const char *orig = var;
 
485
        int len = strlen(var);
 
486
 
 
487
        if (*orig == '@' || *orig == '$') {
 
488
                orig++;
 
489
                len--;
 
490
        } else {
 
491
                PERROR("ASSERT: Found var '%s' without variable prefix\n",
 
492
                       var);
 
493
                return NULL;
 
494
        }
 
495
 
 
496
        if (*orig == '{') {
 
497
                orig++;
 
498
                len--;
 
499
                if (orig[len - 1] != '}') {
 
500
                        PERROR("ASSERT: No matching '}' in variable '%s'\n",
 
501
                                var);
 
502
                        return NULL;
 
503
                } else
 
504
                        len--;
 
505
        }
 
506
 
 
507
        return strndup(orig, len);
 
508
}
 
509
 
 
510
/* returns -1 if value != true or false, otherwise 0 == false, 1 == true */
 
511
int str_to_boolean(const char *value)
 
512
{
 
513
        int retval = -1;
 
514
 
 
515
        if (strcasecmp("TRUE", value) == 0)
 
516
                retval = 1;
 
517
        if (strcasecmp("FALSE", value) == 0)
 
518
                retval = 0;
 
519
        return retval;
 
520
}
 
521
 
 
522
static int warned_uppercase = 0;
 
523
 
 
524
static void warn_uppercase(void)
 
525
{
 
526
        if (!warned_uppercase) {
 
527
                pwarn(_("Uppercase qualifiers \"RWLIMX\" are deprecated, please convert to lowercase\n"
 
528
                        "See the apparmor.d(5) manpage for details.\n"));
 
529
                warned_uppercase = 1;
 
530
        }
 
531
}
 
532
 
 
533
static int parse_sub_mode(const char *str_mode, const char *mode_desc __unused)
 
534
{
 
535
 
 
536
#define IS_DIFF_QUAL(mode, q) (((mode) & AA_MAY_EXEC) && (((mode) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
 
537
 
 
538
        int mode = 0;
 
539
        const char *p;
 
540
 
 
541
        PDEBUG("Parsing mode: %s\n", str_mode);
 
542
 
 
543
        if (!str_mode)
 
544
                return 0;
 
545
 
 
546
        p = str_mode;
 
547
        while (*p) {
 
548
                char this = *p;
 
549
                char next = *(p + 1);
 
550
                char lower;
 
551
                int tmode = 0;
 
552
 
 
553
reeval:
 
554
                switch (this) {
 
555
                case COD_READ_CHAR:
 
556
                        if (read_implies_exec) {
 
557
                                PDEBUG("Parsing mode: found %s READ imply X\n", mode_desc);
 
558
                                mode |= AA_MAY_READ | AA_EXEC_MMAP;
 
559
                        } else {
 
560
                                PDEBUG("Parsing mode: found %s READ\n", mode_desc);
 
561
                                mode |= AA_MAY_READ;
 
562
                        }
 
563
                        break;
 
564
 
 
565
                case COD_WRITE_CHAR:
 
566
                        PDEBUG("Parsing mode: found %s WRITE\n", mode_desc);
 
567
                        if ((mode & AA_MAY_APPEND) && !(mode & AA_MAY_WRITE))
 
568
                                yyerror(_("Conflict 'a' and 'w' perms are mutually exclusive."));
 
569
                        mode |= AA_MAY_WRITE | AA_MAY_APPEND;
 
570
                        break;
 
571
 
 
572
                case COD_APPEND_CHAR:
 
573
                        PDEBUG("Parsing mode: found %s APPEND\n", mode_desc);
 
574
                        if (mode & AA_MAY_WRITE)
 
575
                                yyerror(_("Conflict 'a' and 'w' perms are mutually exclusive."));
 
576
                        mode |= AA_MAY_APPEND;
 
577
                        break;
 
578
 
 
579
                case COD_LINK_CHAR:
 
580
                        PDEBUG("Parsing mode: found %s LINK\n", mode_desc);
 
581
                        mode |= AA_MAY_LINK;
 
582
                        break;
 
583
 
 
584
                case COD_LOCK_CHAR:
 
585
                        PDEBUG("Parsing mode: found %s LOCK\n", mode_desc);
 
586
                        mode |= AA_MAY_LOCK;
 
587
                        break;
 
588
 
 
589
                case COD_INHERIT_CHAR:
 
590
                        PDEBUG("Parsing mode: found INHERIT\n");
 
591
                        if (mode & AA_EXEC_MODIFIERS) {
 
592
                                yyerror(_("Exec qualifier 'i' invalid, conflicting qualifier already specified"));
 
593
                        } else {
 
594
                                if (next != tolower(next))
 
595
                                        warn_uppercase();
 
596
                                mode |= (AA_EXEC_INHERIT | AA_MAY_EXEC);
 
597
                                p++;    /* skip 'x' */
 
598
                        }
 
599
                        break;
 
600
 
 
601
                case COD_UNSAFE_UNCONFINED_CHAR:
 
602
                        tmode = AA_EXEC_UNSAFE;
 
603
                        pwarn(_("Unconfined exec qualifier (%c%c) allows some dangerous environment variables "
 
604
                                "to be passed to the unconfined process; 'man 5 apparmor.d' for details.\n"),
 
605
                              COD_UNSAFE_UNCONFINED_CHAR, COD_EXEC_CHAR);
 
606
                        /* fall through */
 
607
                case COD_UNCONFINED_CHAR:
 
608
                        tmode |= AA_EXEC_UNCONFINED | AA_MAY_EXEC;
 
609
                        PDEBUG("Parsing mode: found UNCONFINED\n");
 
610
                        if (IS_DIFF_QUAL(mode, tmode)) {
 
611
                                yyerror(_("Exec qualifier '%c' invalid, conflicting qualifier already specified"),
 
612
                                        this);
 
613
                        } else {
 
614
                                if (next != tolower(next))
 
615
                                        warn_uppercase();
 
616
                                mode |=  tmode;
 
617
                                p++;    /* skip 'x' */
 
618
                        }
 
619
                        tmode = 0;
 
620
                        break;
 
621
 
 
622
                case COD_UNSAFE_PROFILE_CHAR:
 
623
                case COD_UNSAFE_LOCAL_CHAR:
 
624
                        tmode = AA_EXEC_UNSAFE;
 
625
                        /* fall through */
 
626
                case COD_PROFILE_CHAR:
 
627
                case COD_LOCAL_CHAR:
 
628
                        if (tolower(this) == COD_UNSAFE_PROFILE_CHAR)
 
629
                                tmode |= AA_EXEC_PROFILE | AA_MAY_EXEC;
 
630
                        else
 
631
                        {
 
632
                                tmode |= AA_EXEC_LOCAL | AA_MAY_EXEC;
 
633
                        }
 
634
                        PDEBUG("Parsing mode: found PROFILE\n");
 
635
                        if (tolower(next) == COD_INHERIT_CHAR) {
 
636
                                tmode |= AA_EXEC_INHERIT;
 
637
                                if (IS_DIFF_QUAL(mode, tmode)) {
 
638
                                        yyerror(_("Exec qualifier '%c%c' invalid, conflicting qualifier already specified"), this, next);
 
639
                                } else {
 
640
                                        mode |= tmode;
 
641
                                        p += 2;         /* skip x */
 
642
                                }
 
643
                        } else if (tolower(next) == COD_UNSAFE_UNCONFINED_CHAR) {
 
644
                                tmode |= AA_EXEC_PUX;
 
645
                                if (IS_DIFF_QUAL(mode, tmode)) {
 
646
                                        yyerror(_("Exec qualifier '%c%c' invalid, conflicting qualifier already specified"), this, next);
 
647
                                } else {
 
648
                                        mode |= tmode;
 
649
                                        p += 2;         /* skip x */
 
650
                                }
 
651
                        } else if (IS_DIFF_QUAL(mode, tmode)) {
 
652
                                yyerror(_("Exec qualifier '%c' invalid, conflicting qualifier already specified"), this);
 
653
 
 
654
                        } else {
 
655
                                if (next != tolower(next))
 
656
                                        warn_uppercase();
 
657
                                mode |= tmode;
 
658
                                p++;    /* skip 'x' */
 
659
                        }
 
660
                        tmode = 0;
 
661
                        break;
 
662
 
 
663
                case COD_MMAP_CHAR:
 
664
                        PDEBUG("Parsing mode: found %s MMAP\n", mode_desc);
 
665
                        mode |= AA_EXEC_MMAP;
 
666
                        break;
 
667
 
 
668
                case COD_EXEC_CHAR:
 
669
                        /* this is valid for deny rules, and named transitions
 
670
                         * but invalid for regular x transitions
 
671
                         * sort it out later.
 
672
                         */
 
673
                        mode |= AA_MAY_EXEC;
 
674
                        break;
 
675
 
 
676
                /* error cases */
 
677
 
 
678
                default:
 
679
                        lower = tolower(this);
 
680
                        switch (lower) {
 
681
                        case COD_READ_CHAR:
 
682
                        case COD_WRITE_CHAR:
 
683
                        case COD_APPEND_CHAR:
 
684
                        case COD_LINK_CHAR:
 
685
                        case COD_INHERIT_CHAR:
 
686
                        case COD_MMAP_CHAR:
 
687
                        case COD_EXEC_CHAR:
 
688
                                PDEBUG("Parsing mode: found invalid upper case char %c\n", this);
 
689
                                warn_uppercase();
 
690
                                this = lower;
 
691
                                goto reeval;
 
692
                                break;
 
693
                        default:
 
694
                                yyerror(_("Internal: unexpected mode character '%c' in input"),
 
695
                                        this);
 
696
                                break;
 
697
                        }
 
698
                        break;
 
699
                }
 
700
 
 
701
                p++;
 
702
        }
 
703
 
 
704
        PDEBUG("Parsed mode: %s 0x%x\n", str_mode, mode);
 
705
 
 
706
        return mode;
 
707
}
 
708
 
 
709
int parse_mode(const char *str_mode)
 
710
{
 
711
        int tmp, mode = 0;
 
712
        tmp = parse_sub_mode(str_mode, "");
 
713
        mode = SHIFT_MODE(tmp, AA_USER_SHIFT);
 
714
        mode |= SHIFT_MODE(tmp, AA_OTHER_SHIFT);
 
715
        if (mode & ~AA_VALID_PERMS)
 
716
                yyerror(_("Internal error generated invalid perm 0x%llx\n"), mode);
 
717
        return mode;
 
718
}
 
719
 
 
720
struct cod_entry *new_entry(char *namespace, char *id, int mode, char *link_id)
 
721
{
 
722
        struct cod_entry *entry = NULL;
 
723
 
 
724
        entry = (struct cod_entry *)calloc(1, sizeof(struct cod_entry));
 
725
        if (!entry)
 
726
                return NULL;
 
727
 
 
728
        entry->namespace = namespace;
 
729
        entry->name = id;
 
730
        entry->link_name = link_id;
 
731
        entry->mode = mode;
 
732
        entry->audit = 0;
 
733
        entry->deny = FALSE;
 
734
 
 
735
        entry->pattern_type = ePatternInvalid;
 
736
        entry->pat.regex = NULL;
 
737
 
 
738
        entry->next = NULL;
 
739
 
 
740
        PDEBUG(" Insertion of: (%s)\n", entry->name);
 
741
        return entry;
 
742
}
 
743
 
 
744
struct cod_entry *copy_cod_entry(struct cod_entry *orig)
 
745
{
 
746
        struct cod_entry *entry = NULL;
 
747
 
 
748
        entry = (struct cod_entry *)calloc(1, sizeof(struct cod_entry));
 
749
        if (!entry)
 
750
                return NULL;
 
751
 
 
752
        entry->namespace = orig->namespace ? strdup(orig->namespace) : NULL;
 
753
        entry->name = strdup(orig->name);
 
754
        entry->link_name = orig->link_name ? strdup(orig->link_name) : NULL;
 
755
        entry->mode = orig->mode;
 
756
        entry->audit = orig->audit;
 
757
        entry->deny = orig->deny;
 
758
 
 
759
        /* XXX - need to create copies of the patterns, too */
 
760
        entry->pattern_type = orig->pattern_type;
 
761
        entry->pat.regex = NULL;
 
762
 
 
763
        entry->next = orig->next;
 
764
 
 
765
        return entry;
 
766
}
 
767
 
 
768
void free_cod_entries(struct cod_entry *list)
 
769
{
 
770
        if (!list)
 
771
                return;
 
772
        if (list->next)
 
773
                free_cod_entries(list->next);
 
774
        if (list->namespace)
 
775
                free(list->namespace);
 
776
        if (list->name)
 
777
                free(list->name);
 
778
        if (list->link_name)
 
779
                free(list->link_name);
 
780
        if (list->pat.regex)
 
781
                free(list->pat.regex);
 
782
        free(list);
 
783
}
 
784
 
 
785
void free_mnt_entries(struct mnt_entry *list)
 
786
{
 
787
        if (!list)
 
788
                return;
 
789
        if (list->next)
 
790
                free_mnt_entries(list->next);
 
791
        free(list->mnt_point);
 
792
        free(list->device);
 
793
        free_value_list(list->dev_type);
 
794
        free_value_list(list->opts);
 
795
 
 
796
        free(list);
 
797
}
 
798
 
 
799
static void debug_base_perm_mask(int mask)
 
800
{
 
801
        if (HAS_MAY_READ(mask))
 
802
                printf("%c", COD_READ_CHAR);
 
803
        if (HAS_MAY_WRITE(mask))
 
804
                printf("%c", COD_WRITE_CHAR);
 
805
        if (HAS_MAY_APPEND(mask))
 
806
                printf("%c", COD_APPEND_CHAR);
 
807
        if (HAS_MAY_LINK(mask))
 
808
                printf("%c", COD_LINK_CHAR);
 
809
        if (HAS_MAY_LOCK(mask))
 
810
                printf("%c", COD_LOCK_CHAR);
 
811
        if (HAS_EXEC_MMAP(mask))
 
812
                printf("%c", COD_MMAP_CHAR);
 
813
        if (HAS_MAY_EXEC(mask))
 
814
                printf("%c", COD_EXEC_CHAR);
 
815
}
 
816
 
 
817
void debug_cod_entries(struct cod_entry *list)
 
818
{
 
819
        struct cod_entry *item = NULL;
 
820
 
 
821
        printf("--- Entries ---\n");
 
822
 
 
823
        list_for_each(list, item) {
 
824
                if (!item)
 
825
                        printf("Item is NULL!\n");
 
826
 
 
827
                printf("Mode:\t");
 
828
                if (HAS_CHANGE_PROFILE(item->mode))
 
829
                        printf(" change_profile");
 
830
                if (HAS_EXEC_UNSAFE(item->mode))
 
831
                        printf(" unsafe");
 
832
                debug_base_perm_mask(SHIFT_TO_BASE(item->mode, AA_USER_SHIFT));
 
833
                printf(":");
 
834
                debug_base_perm_mask(SHIFT_TO_BASE(item->mode, AA_OTHER_SHIFT));
 
835
                if (item->name)
 
836
                        printf("\tName:\t(%s)\n", item->name);
 
837
                else
 
838
                        printf("\tName:\tNULL\n");
 
839
 
 
840
                if (item->namespace)
 
841
                        printf("\tNamespace:\t(%s)\n", item->namespace);
 
842
 
 
843
                if (AA_LINK_BITS & item->mode)
 
844
                        printf("\tlink:\t(%s)\n", item->link_name ? item->link_name : "/**");
 
845
 
 
846
        }
 
847
}
 
848
 
 
849
void debug_flags(struct codomain *cod)
 
850
{
 
851
        printf("Profile Mode:\t");
 
852
 
 
853
        if (cod->flags.complain)
 
854
                printf("Complain");
 
855
        else
 
856
                printf("Enforce");
 
857
 
 
858
        if (cod->flags.audit)
 
859
                printf(", Audit");
 
860
 
 
861
        if (cod->flags.hat)
 
862
                printf(", Hat");
 
863
 
 
864
        printf("\n");
 
865
}
 
866
 
 
867
static const char *capnames[] = {
 
868
        "chown",
 
869
        "dac_override",
 
870
        "dac_read_search",
 
871
        "fowner",
 
872
        "fsetid",
 
873
        "kill",
 
874
        "setgid",
 
875
        "setuid",
 
876
        "setpcap",
 
877
        "linux_immutable",
 
878
        "net_bind_service",
 
879
        "net_broadcast",
 
880
        "net_admin",
 
881
        "net_raw",
 
882
        "ipc_lock",
 
883
        "ipc_owner",
 
884
        "sys_module",
 
885
        "sys_rawio",
 
886
        "sys_chroot",
 
887
        "sys_ptrace",
 
888
        "sys_pacct",
 
889
        "sys_admin",
 
890
        "sys_boot",
 
891
        "sys_nice",
 
892
        "sys_resource",
 
893
        "sys_time",
 
894
        "sys_tty_config",
 
895
        "mknod",
 
896
        "lease",
 
897
        "audit_write",
 
898
        "audit_control",
 
899
        "setfcap",
 
900
        "mac_override"
 
901
        "syslog",
 
902
};
 
903
 
 
904
const char *capability_to_name(unsigned int cap)
 
905
{
 
906
        const char *capname;
 
907
 
 
908
        capname = (cap < (sizeof(capnames) / sizeof(char *))
 
909
                   ? capnames[cap] : "invalid-capability");
 
910
 
 
911
        return capname;
 
912
}
 
913
 
 
914
void __debug_capabilities(uint64_t capset, const char *name)
 
915
{
 
916
        unsigned int i;
 
917
 
 
918
        printf("%s:", name);
 
919
        for (i = 0; i < (sizeof(capnames)/sizeof(char *)); i++) {
 
920
                if (((1ull << i) & capset) != 0) {
 
921
                        printf (" %s", capability_to_name(i));
 
922
                }
 
923
        }
 
924
        printf("\n");
 
925
}
 
926
void debug_capabilities(struct codomain *cod)
 
927
{
 
928
        if (cod->capabilities != 0ull)
 
929
                __debug_capabilities(cod->capabilities, "Capabilities");
 
930
        if (cod->audit_caps != 0ull)
 
931
                __debug_capabilities(cod->audit_caps, "Audit Caps");
 
932
        if (cod->deny_caps != 0ull)
 
933
                __debug_capabilities(cod->deny_caps, "Deny Caps");
 
934
        if (cod->quiet_caps != 0ull)
 
935
                __debug_capabilities(cod->quiet_caps, "Quiet Caps");
 
936
}
 
937
 
 
938
void debug_cod_list(struct codomain *cod)
 
939
{
 
940
        if (cod->namespace)
 
941
                printf("Namespace:\t\t%s\n", cod->namespace);
 
942
 
 
943
        if (cod->name)
 
944
                printf("Name:\t\t%s\n", cod->name);
 
945
        else
 
946
                printf("Name:\t\tNULL\n");
 
947
 
 
948
        if (cod->local)
 
949
                printf("Local To:\t%s\n", cod->parent->name);
 
950
 
 
951
        debug_flags(cod);
 
952
        
 
953
        debug_capabilities(cod);
 
954
 
 
955
        if (cod->entries)
 
956
                debug_cod_entries(cod->entries);
 
957
 
 
958
        printf("\n");
 
959
        dump_policy_hats(cod);
 
960
}
 
961
 
 
962
struct value_list *new_value_list(char *value)
 
963
{
 
964
        struct value_list *val = calloc(1, sizeof(struct value_list));
 
965
        if (val)
 
966
                val->value = value;
 
967
        return val;
 
968
}
 
969
 
 
970
void free_value_list(struct value_list *list)
 
971
{
 
972
        struct value_list *next;
 
973
 
 
974
        while (list) {
 
975
                next = list->next;
 
976
                if (list->value)
 
977
                        free(list->value);
 
978
                free(list);
 
979
                list = next;
 
980
        }
 
981
}
 
982
 
 
983
struct value_list *dup_value_list(struct value_list *list)
 
984
{
 
985
        struct value_list *entry, *dup, *head = NULL;
 
986
        char *value;
 
987
 
 
988
        list_for_each(list, entry) {
 
989
                value = NULL;
 
990
                if (list->value) {
 
991
                        value = strdup(list->value);
 
992
                        if (!value)
 
993
                                goto fail2;
 
994
                }
 
995
                dup = new_value_list(value);
 
996
                if (!dup)
 
997
                        goto fail;
 
998
                if (head)
 
999
                        list_append(head, dup);
 
1000
                else
 
1001
                        head = dup;
 
1002
        }
 
1003
 
 
1004
        return head;
 
1005
 
 
1006
fail:
 
1007
        free(value);
 
1008
fail2:
 
1009
        free_value_list(head);
 
1010
 
 
1011
        return NULL;
 
1012
}
 
1013
 
 
1014
void print_value_list(struct value_list *list)
 
1015
{
 
1016
        struct value_list *entry;
 
1017
 
 
1018
        if (!list)
 
1019
                return;
 
1020
 
 
1021
        fprintf(stderr, "%s", list->value);
 
1022
        list = list->next;
 
1023
        list_for_each(list, entry) {
 
1024
                fprintf(stderr, ", %s", entry->value);
 
1025
        }
 
1026
}
 
1027
 
 
1028
struct cond_entry *new_cond_entry(char *name, struct value_list *list)
 
1029
{
 
1030
        struct cond_entry *ent = calloc(1, sizeof(struct cond_entry));
 
1031
        if (ent) {
 
1032
                ent->name = name;
 
1033
                ent->vals = list;
 
1034
        }
 
1035
 
 
1036
        return ent;
 
1037
}
 
1038
 
 
1039
void free_cond_entry(struct cond_entry *ent)
 
1040
{
 
1041
        if (ent) {
 
1042
                free(ent->name);
 
1043
                free_value_list(ent->vals);
 
1044
                free(ent);
 
1045
        }
 
1046
}
 
1047
 
 
1048
void print_cond_entry(struct cond_entry *ent)
 
1049
{
 
1050
        if (ent) {
 
1051
                fprintf(stderr, "%s=(", ent->name);
 
1052
                print_value_list(ent->vals);
 
1053
                fprintf(stderr, ")\n");
 
1054
        }
 
1055
}
 
1056
 
 
1057
#ifdef UNIT_TEST
 
1058
int test_str_to_boolean(void)
 
1059
{
 
1060
        int rc = 0;
 
1061
        int retval;
 
1062
 
 
1063
        retval = str_to_boolean("TRUE");
 
1064
        MY_TEST(retval == 1, "str2bool for TRUE");
 
1065
 
 
1066
        retval = str_to_boolean("TrUe");
 
1067
        MY_TEST(retval == 1, "str2bool for TrUe");
 
1068
 
 
1069
        retval = str_to_boolean("false");
 
1070
        MY_TEST(retval == 0, "str2bool for false");
 
1071
 
 
1072
        retval = str_to_boolean("flase");
 
1073
        MY_TEST(retval == -1, "str2bool for flase");
 
1074
 
 
1075
        return rc;
 
1076
}
 
1077
 
 
1078
int test_processunquoted(void)
 
1079
{
 
1080
        int rc = 0;
 
1081
        char *teststring, *processedstring;
 
1082
 
 
1083
        teststring = "";
 
1084
        MY_TEST(strcmp(teststring, processunquoted(teststring, strlen(teststring))) == 0,
 
1085
                        "processunquoted on empty string");
 
1086
 
 
1087
        teststring = "123\\421123";
 
1088
        MY_TEST(strcmp(teststring, processunquoted(teststring, strlen(teststring))) == 0,
 
1089
                        "processunquoted on invalid octal");
 
1090
 
 
1091
/* Oh wow, our octal processing is busticated - FIXME
 
1092
        teststring = "123\\109123";
 
1093
        processedstring = "123\109123";
 
1094
        MY_TEST(strcmp(processedstring, processunquoted(teststring, strlen(teststring))) == 0,
 
1095
                        "processunquoted on octal 10");
 
1096
 
 
1097
        teststring = "123\\189123";
 
1098
        processedstring = "123\189123";
 
1099
        MY_TEST(strcmp(processedstring, processunquoted(teststring, strlen(teststring))) == 0,
 
1100
                        "processunquoted on octal 10");
 
1101
*/
 
1102
 
 
1103
        return rc;
 
1104
}
 
1105
 
 
1106
int test_processquoted(void)
 
1107
{
 
1108
        int rc = 0;
 
1109
        char *teststring, *processedstring;
 
1110
        char *out;
 
1111
 
 
1112
        teststring = "";
 
1113
        out = processquoted(teststring, strlen(teststring));
 
1114
        MY_TEST(strcmp(teststring, out) == 0,
 
1115
                        "processquoted on empty string");
 
1116
        free(out);
 
1117
 
 
1118
        teststring = "\"abcdefg\"";
 
1119
        processedstring = "abcdefg";
 
1120
        out = processquoted(teststring, strlen(teststring));
 
1121
        MY_TEST(strcmp(processedstring, out) == 0,
 
1122
                        "processquoted on simple string");
 
1123
        free(out);
 
1124
 
 
1125
        teststring = "\"abcd\\tefg\"";
 
1126
        processedstring = "abcd\tefg";
 
1127
        out = processquoted(teststring, strlen(teststring));
 
1128
        MY_TEST(strcmp(processedstring, out) == 0,
 
1129
                        "processquoted on string with tab");
 
1130
        free(out);
 
1131
 
 
1132
        teststring = "\"abcdefg\\\"";
 
1133
        processedstring = "abcdefg\\";
 
1134
        out = processquoted(teststring, strlen(teststring));
 
1135
        MY_TEST(strcmp(processedstring, out) == 0,
 
1136
                        "processquoted on trailing slash");
 
1137
        free(out);
 
1138
 
 
1139
        teststring = "\"a\\\\bcdefg\"";
 
1140
        processedstring = "a\\bcdefg";
 
1141
        out = processquoted(teststring, strlen(teststring));
 
1142
        MY_TEST(strcmp(processedstring, out) == 0,
 
1143
                        "processquoted on quoted slash");
 
1144
        free(out);
 
1145
 
 
1146
        teststring = "\"a\\\"bcde\\\"fg\"";
 
1147
        processedstring = "a\"bcde\"fg";
 
1148
        out = processquoted(teststring, strlen(teststring));
 
1149
        MY_TEST(strcmp(processedstring, out) == 0,
 
1150
                        "processquoted on quoted quotes");
 
1151
        free(out);
 
1152
 
 
1153
        teststring = "\"\\rabcdefg\"";
 
1154
        processedstring = "\rabcdefg";
 
1155
        out = processquoted(teststring, strlen(teststring));
 
1156
        MY_TEST(strcmp(processedstring, out) == 0,
 
1157
                        "processquoted on quoted \\r");
 
1158
        free(out);
 
1159
 
 
1160
        teststring = "\"abcdefg\\n\"";
 
1161
        processedstring = "abcdefg\n";
 
1162
        out = processquoted(teststring, strlen(teststring));
 
1163
        MY_TEST(strcmp(processedstring, out) == 0,
 
1164
                        "processquoted on quoted \\n");
 
1165
        free(out);
 
1166
 
 
1167
        teststring = "\"\\Uabc\\Ndefg\\x\"";
 
1168
        processedstring = "\\Uabc\\Ndefg\\x";
 
1169
        out = processquoted(teststring, strlen(teststring));
 
1170
        MY_TEST(strcmp(processedstring, out) == 0,
 
1171
                        "processquoted passthrough on invalid quoted chars");
 
1172
        free(out);
 
1173
 
 
1174
        teststring = "\"abc\\042defg\"";
 
1175
        processedstring = "abc\"defg";
 
1176
        out = processquoted(teststring, strlen(teststring));
 
1177
        MY_TEST(strcmp(processedstring, out) == 0,
 
1178
                        "processquoted on quoted octal \\042");
 
1179
        free(out);
 
1180
 
 
1181
        teststring = "\"abcdefg\\176\"";
 
1182
        processedstring = "abcdefg~";
 
1183
        out = processquoted(teststring, strlen(teststring));
 
1184
        MY_TEST(strcmp(processedstring, out) == 0,
 
1185
                        "processquoted on quoted octal \\176");
 
1186
        free(out);
 
1187
 
 
1188
        /* yes, our octal processing is lame; patches accepted */
 
1189
        teststring = "\"abc\\42defg\"";
 
1190
        processedstring = "abc\\42defg";
 
1191
        out = processquoted(teststring, strlen(teststring));
 
1192
        MY_TEST(strcmp(processedstring, out) == 0,
 
1193
                        "processquoted passthrough quoted invalid octal \\42");
 
1194
        free(out);
 
1195
 
 
1196
        teststring = "\"abcdefg\\04\"";
 
1197
        processedstring = "abcdefg\\04";
 
1198
        out = processquoted(teststring, strlen(teststring));
 
1199
        MY_TEST(strcmp(processedstring, out) == 0,
 
1200
                        "processquoted passthrough quoted invalid trailing octal \\04");
 
1201
        free(out);
 
1202
 
 
1203
        return rc;
 
1204
}
 
1205
 
 
1206
int main(void)
 
1207
{
 
1208
        int rc = 0;
 
1209
        int retval;
 
1210
 
 
1211
        retval = test_str_to_boolean();
 
1212
        if (retval != 0)
 
1213
                rc = retval;
 
1214
 
 
1215
        retval = test_processunquoted();
 
1216
        if (retval != 0)
 
1217
                rc = retval;
 
1218
 
 
1219
        retval = test_processquoted();
 
1220
        if (retval != 0)
 
1221
                rc = retval;
 
1222
 
 
1223
        return rc;
 
1224
}
 
1225
#endif /* UNIT_TEST */