Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/bltins/regress.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1982-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* David Korn <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* regression test intercept control
23
* enable with SHOPT_REGRESS==1 in Makefile
24
* not for production use
25
* see --man for details
26
* all string constants inline here instead of in data/...
27
*
28
* David Korn
29
* at&t research
30
*/
31
32
#include "defs.h"
33
34
#if SHOPT_REGRESS
35
36
#include <error.h>
37
#include <ls.h>
38
#include "io.h"
39
#include "builtins.h"
40
#include <tmx.h>
41
42
#define REGRESS_HEADER "ksh:REGRESS:"
43
44
#define TRACE(r,i,f) sh_regress(REGRESS_##r, i, sfprints f, __LINE__, __FILE__)
45
46
static const char usage[] =
47
"[-1p0?\n@(#)$Id: __regress__ (AT&T Research) 2009-03-29 $\n]"
48
USAGE_LICENSE
49
"[+NAME?__regress__ - shell regression test intercept control]"
50
"[+DESCRIPTION?\b__regress__\b controls the regression test intercepts "
51
"for shells compiled with SHOPT_REGRESS==1. Shells compiled this way are "
52
"for testing only. In addition to \b__regress__\b and the \b--regress\b "
53
"command line option, these shells may contain system library function "
54
"intercepts that behave different from the native counterparts.]"
55
"[+?Each option controls a different test and possibly a different set "
56
"of intercepts. The options are interpreted \bdd\b(1) style -- '-' or "
57
"'--' prefix not required. This simplifies the specification of the "
58
"command line \b--regress\b=\avalue\a option, where \avalue\a is passed "
59
"as an option to the \b__regress__\b builtin. Typically regression test "
60
"intercepts are enabled with one or more command line \b--regress\b "
61
"options, with optional specific calls to \b__regress__\b in test "
62
"scripts to enable/disable intercepts as the test progresses.]"
63
"[+?Each enabled intercept may result in trace lines of the form \b" REGRESS_HEADER
64
"\aoption\a:\aintercept\a:\ainfo\a on the standard error, where "
65
"\aoption\a is one of the options below, \aintercept\a is the name of "
66
"the specific intercept for \aoption\a, and \ainfo\a is \aoption\a "
67
"specific information. Unless noted otherwise, one regression test trace "
68
"line is produced each time an enabled intercept is called.]"
69
"[101:egid?The intercept effective gid is set to \aoriginal-egid\a. The "
70
"effective gid of the underlying system process is not affected. The "
71
"trace line info is either \begid==rgid\b or \begid!=rgid\b. The "
72
"intercepts are:]#?[original-egid:=1]"
73
"{"
74
"[+getegid()?The intercept effecive gid is returned. The "
75
"\bsetgid\b() intercept may change this between the real gid and "
76
"\aoriginal-egid\a.]"
77
"[+setgid(gid)?Sets the intercept effective gid to \agid\a. "
78
"Fails if \agid\a is neither the real gid nor "
79
"\aoriginal-egid\a.]"
80
"}"
81
"[102:euid?The intercept effective uid is set to \aoriginal-euid\a. The "
82
"effective uid of the underlying system process is not affected. The "
83
"trace line info is either \beuid==ruid\b or \beuid!=ruid\b. The "
84
"intercepts are:]#?[original-euid:=1]"
85
"{"
86
"[+geteuid()?The intercept effecive uid is returned. The "
87
"\bsetuid\b() intercept may change this between the real uid and "
88
"\aoriginal-euid\a.]"
89
"[+setuid(uid)?Sets the intercept effective uid to \auid\a. "
90
"Fails if \auid\a is neither the real uid nor "
91
"\aoriginal-euid\a.]"
92
"}"
93
"[103:p_suid?Specifies a value for SHOPT_P_SUID. Effective uids greater "
94
"than the non-privileged-uid disable the priveleged mode. The intercepts "
95
"are:]#?[non-privileged-uid:=1]"
96
"{"
97
"[+SHOPT_P_SUID?The SHOPT_P_SUID macro value is overridden by "
98
"\bp_suid\b. A trace line is output for each SHOPT_P_SUID "
99
"access.]"
100
"}"
101
"[104:source?The intercepts are:]"
102
"{"
103
"[+sh_source()?The trace line info is the path of the script "
104
"being sourced. Used to trace shell startup scripts.]"
105
"}"
106
"[105:etc?Map file paths matching \b/etc/\b* to \aetc-dir\a/*. The "
107
"intercepts are:]:[etc-dir:=/etc]"
108
"{"
109
"[+sh_open()?Paths matching \b/etc/\b* are changed to "
110
"\aetc-dir\a/*.]"
111
"}"
112
"[+SEE ALSO?\bksh\b(1), \bregress\b(1), \brt\b(1)]"
113
;
114
115
static const char* regress_options[] =
116
{
117
"ERROR",
118
"egid",
119
"euid",
120
"p_suid",
121
"source",
122
"etc",
123
};
124
125
void sh_regress_init(Shell_t* shp)
126
{
127
static Regress_t state;
128
129
shp->regress = &state;
130
}
131
132
/*
133
* regress info trace output
134
*/
135
136
void sh_regress(unsigned int index, const char* intercept, const char* info, unsigned int line, const char* file)
137
{
138
char* name;
139
char buf[16];
140
141
if (index >= 1 && index <= elementsof(regress_options))
142
name = (char*)regress_options[index];
143
else
144
sfsprintf(name = buf, sizeof(buf), "%u", index);
145
sfprintf(sfstderr, REGRESS_HEADER "%s:%s:%s\n", name, intercept, fmtesc(info));
146
}
147
148
/*
149
* egid intercepts
150
*/
151
152
static gid_t intercept_sgid = 0;
153
static gid_t intercept_egid = -1;
154
static gid_t intercept_rgid = -1;
155
156
gid_t getegid(void)
157
{
158
if (intercept_rgid == -1)
159
intercept_rgid = getgid();
160
if (sh_isregress(REGRESS_egid))
161
{
162
TRACE(egid, "getegid", ("%s", intercept_egid == intercept_rgid ? "egid==rgid" : "egid!=rgid"));
163
return intercept_egid;
164
}
165
return intercept_rgid;
166
}
167
168
int setgid(gid_t gid)
169
{
170
if (intercept_rgid == -1)
171
intercept_rgid = getgid();
172
if (sh_isregress(REGRESS_egid))
173
{
174
if (gid != intercept_rgid && gid != intercept_sgid)
175
{
176
TRACE(egid, "setgid", ("%s", "EPERM"));
177
errno = EPERM;
178
return -1;
179
}
180
intercept_egid = gid;
181
TRACE(egid, "setgid", ("%s", intercept_egid == intercept_rgid ? "egid==rgid" : "egid!=rgid"));
182
}
183
else if (gid != intercept_rgid)
184
{
185
errno = EPERM;
186
return -1;
187
}
188
return 0;
189
}
190
191
/*
192
* euid intercepts
193
*/
194
195
static uid_t intercept_suid = 0;
196
static uid_t intercept_euid = -1;
197
static uid_t intercept_ruid = -1;
198
199
uid_t geteuid(void)
200
{
201
if (intercept_ruid == -1)
202
intercept_ruid = getuid();
203
if (sh_isregress(REGRESS_euid))
204
{
205
TRACE(euid, "geteuid", ("%s", intercept_euid == intercept_ruid ? "euid==ruid" : "euid!=ruid"));
206
return intercept_euid;
207
}
208
return intercept_ruid;
209
}
210
211
int setuid(uid_t uid)
212
{
213
if (intercept_ruid == -1)
214
intercept_ruid = getuid();
215
if (sh_isregress(REGRESS_euid))
216
{
217
if (uid != intercept_ruid && uid != intercept_suid)
218
{
219
TRACE(euid, "setuid", ("%s", "EPERM"));
220
errno = EPERM;
221
return -1;
222
}
223
intercept_euid = uid;
224
TRACE(euid, "setuid", ("%s", intercept_euid == intercept_ruid ? "euid==ruid" : "euid!=ruid"));
225
}
226
else if (uid != intercept_ruid)
227
{
228
errno = EPERM;
229
return -1;
230
}
231
return 0;
232
}
233
234
/*
235
* p_suid intercept
236
*/
237
238
static uid_t intercept_p_suid = 0x7fffffff;
239
240
uid_t sh_regress_p_suid(unsigned int line, const char* file)
241
{
242
REGRESS(p_suid, "SHOPT_P_SUID", ("%d", intercept_p_suid));
243
return intercept_p_suid;
244
}
245
246
/*
247
* p_suid intercept
248
*/
249
250
static char* intercept_etc = 0;
251
252
char* sh_regress_etc(const char* path, unsigned int line, const char* file)
253
{
254
REGRESS(etc, "sh_open", ("%s => %s%s", path, intercept_etc, path+4));
255
return intercept_etc;
256
}
257
258
/*
259
* __regress__ builtin
260
*/
261
262
int b___regress__(int argc, char** argv, Shbltin_t *context)
263
{
264
register Shell_t* shp = context->shp;
265
int n;
266
267
for (;;)
268
{
269
switch (n = optget(argv, usage))
270
{
271
case '?':
272
errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
273
break;
274
case ':':
275
errormsg(SH_DICT, 2, "%s", opt_info.arg);
276
break;
277
case 0:
278
break;
279
default:
280
if (n < -100)
281
{
282
n = -(n + 100);
283
if (opt_info.arg || opt_info.number)
284
sh_onregress(n);
285
else
286
sh_offregress(n);
287
switch (n)
288
{
289
case REGRESS_egid:
290
if (sh_isregress(n))
291
{
292
intercept_egid = intercept_sgid = (gid_t)opt_info.number;
293
TRACE(egid, argv[0], ("%d", intercept_egid));
294
}
295
else
296
TRACE(egid, argv[0], ("%s", "off"));
297
break;
298
case REGRESS_euid:
299
if (sh_isregress(n))
300
{
301
intercept_euid = intercept_suid = (uid_t)opt_info.number;
302
TRACE(euid, argv[0], ("%d", intercept_euid));
303
}
304
else
305
TRACE(euid, argv[0], ("%s", "off"));
306
break;
307
case REGRESS_p_suid:
308
if (sh_isregress(n))
309
{
310
intercept_p_suid = (uid_t)opt_info.number;
311
TRACE(p_suid, argv[0], ("%d", intercept_p_suid));
312
}
313
else
314
TRACE(p_suid, argv[0], ("%s", "off"));
315
break;
316
case REGRESS_source:
317
TRACE(source, argv[0], ("%s", sh_isregress(n) ? "on" : "off"));
318
break;
319
case REGRESS_etc:
320
if (sh_isregress(n))
321
{
322
intercept_etc = opt_info.arg;
323
TRACE(etc, argv[0], ("%s", intercept_etc));
324
}
325
else
326
TRACE(etc, argv[0], ("%s", "off"));
327
break;
328
}
329
}
330
continue;
331
}
332
break;
333
}
334
if (error_info.errors || *(argv + opt_info.index))
335
errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NiL));
336
return 0;
337
}
338
339
#else
340
341
NoN(regress)
342
343
#endif
344
345