File: security.c

package info (click to toggle)
audacity 2.1.2-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 86,844 kB
  • sloc: ansic: 225,005; cpp: 221,240; sh: 27,327; python: 16,896; makefile: 8,186; lisp: 8,002; perl: 317; xml: 307; sed: 16
file content (174 lines) | stat: -rw-r--r-- 5,139 bytes parent folder | download | duplicates (2)
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
/* security.c -- manage access to files and audio */
/* Roger B. Dannenberg
 * July 2014
 */

#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <xlisp.h>

static void find_full_path(const char *filename, char *fullname);
static int in_tree(const char *fullname, char *secure_read_path);
static int full_name(const char *filename);
static int file_sep(char c);

/* run_time_limit is a feature to shut down infinite loops
 * calls to oscheck are counted. These occur at around 66Hz
 * on a 2010 vintage laptop, so a value of 66 is roughly 1 CPU
 * second of computation. The rate fluctuates depending on
 * the computation, so it is a very rough guide, but then if
 * you are restricting CPU time, you'll probably want to pad
 * the expected time by a factor of at least 2, so hopefully
 * exact numbers are not important. The default is 0, meaning
 * no limit. Set the limit from the command line with -L. 
 * Read the current run time by calling (GET-RUN-TIME) 
 */
int run_time_limit = 0;

/* memory_limit is a feature to shut down rampant memory
 * allocation which tends to lead to thrashing on a virtual
 * (memory) machine. The number is roughly the number of
 * megabytes of sample and cons cell memory that can be
 * allocated. The default is 0 which means no limit.
 */
int memory_limit = 0;

/* run_time is the current run time -- incremented by oscheck() */
int run_time = 0;

/* secure_read_path is NULL if reading any file is permitted
 * o.w. secure_read_path is a semicolon-separated list of 
 * paths to directory trees that are readable
 */
char *secure_read_path = NULL;

/* safe_write_path is NULL if writing any file is permitted
 * o.w. safe_write_path is a semicolon-separated list of
 * paths to directory tress that are writeable
 */
char *safe_write_path = NULL;

/* ok_to_open - true if it is OK to open the file under
 *       the security model implied by secure_read_path
 *       and safe_write_path
 */
int ok_to_open(const char *filename, const char *mode)
{
    char fullname[STRMAX];
    if (strchr(mode, 'r')) { /* asking for read permission */
	if (secure_read_path) { /* filename must be in path */
	    find_full_path(filename, fullname);
	    if (!in_tree(fullname, secure_read_path)) return FALSE;
	}
    }
    if (strchr(mode, 'w')) { /* asking for write permission */
	if (safe_write_path) { /* filename must be in path */
	    find_full_path(filename, fullname);
	    if (!in_tree(fullname, safe_write_path)) return FALSE;
	}
    }
    return TRUE;
}


/* find_full_path - find full path corresponding to filename */
/**/
void find_full_path(const char *filename, char *fullname)
{
    if (full_name(filename)) {
	strncpy(fullname, filename, STRMAX);
	fullname[STRMAX - 1] = 0;
	return;
    }
    if (!getcwd(fullname, STRMAX)) {
	/* something is really wrong. Pretend we found a
	   cwd that will not match anything */
	goto error;
    }
    /* see if we need a separator (probably) */
    int len = strlen(fullname);
    if (!file_sep(fullname[len - 1])) {
	fullname[len++] = '/';
	if (len >= STRMAX) goto error; 
    }
    /* append filename to fullname */
    strncpy(fullname + len, filename, STRMAX - len);
    fullname[STRMAX - 1] = 0; /* just in case of overflow */
    /* if windows, replace \ with / to simplify the rest */
    char *loc = fullname;
    if (os_pathchar != '/') {
        while ((loc = strchr(loc, os_pathchar))) {
	    *loc = '/';
	}
    }
    /* strip out .. and . */
    while ((loc = strstr(fullname, "/.."))) {
	/* back up to separator */
	if (loc == fullname) goto error;
	char *loc2 = loc - 1;
	while (*loc2 != '/') {
	    loc2--;
	    if (loc2 <= fullname) goto error;
	}
	/* now loc2 points to /parent/.., and loc points to /.. */
	/* copy from beyond /.. to loc2 */
	memmove(loc2, loc, strlen(loc) + 1);
    }
    return;
  error:
    strcpy(fullname, "//////");
    return;
}


static int file_sep(char c)
{
    return (c == os_pathchar || c == '/');
}


/* full_name - test if filename is a full path */
/**/
static int full_name(const char *filename)
{
    if (!filename) return FALSE;
    if (filename[0] == os_pathchar) return TRUE;
    /* windows allows '/' instead of '\' */
    if (filename[0] == '/') return TRUE;
    if (strlen(filename) > 2 &&
	isalpha(filename[0]) &&
	filename[1] == ':') return TRUE;
    return FALSE;
}


static int in_tree(const char *fullname, char *secure_read_path)
{
    /* fullname is in a tree if a path in secure_read_path
       is a prefix of fullname
       Algorithm: extract each path, check for prefix
    */
    char path[STRMAX];
    while (secure_read_path && *secure_read_path) {
	/* skip over separator */
	while (*secure_read_path == os_sepchar ||
	       *secure_read_path == ';') secure_read_path++;
	/* find next directory and copy into path*/
	path[0] = 0;
	int i = 0;
	while (*secure_read_path && (*secure_read_path != os_sepchar &&
				     *secure_read_path != ';')) {
	    path[i++] = *secure_read_path++;
	}
	path[i] = 0;
	/* see if directory is a prefix of fullname */
	if (strstr(fullname, path) == fullname) {
	    return TRUE;
	}
    }
    return FALSE;
}