1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
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/...
42 #define REGRESS_HEADER "ksh:REGRESS:"
44 #define TRACE(r,i,f) sh_regress(REGRESS_##r, i, sfprints f, __LINE__, __FILE__)
46 static const char usage
[] =
47 "[-1p0?\n@(#)$Id: __regress__ (AT&T Research) 2009-03-29 $\n]"
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]"
74 "[+getegid()?The intercept effecive gid is returned. The "
75 "\bsetgid\b() intercept may change this between the real gid and "
77 "[+setgid(gid)?Sets the intercept effective gid to \agid\a. "
78 "Fails if \agid\a is neither the real gid nor "
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]"
86 "[+geteuid()?The intercept effecive uid is returned. The "
87 "\bsetuid\b() intercept may change this between the real uid and "
89 "[+setuid(uid)?Sets the intercept effective uid to \auid\a. "
90 "Fails if \auid\a is neither the real uid nor "
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]"
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 "
101 "[104:source?The intercepts are:]"
103 "[+sh_source()?The trace line info is the path of the script "
104 "being sourced. Used to trace shell startup scripts.]"
106 "[105:etc?Map file paths matching \b/etc/\b* to \aetc-dir\a/*. The "
107 "intercepts are:]:[etc-dir:=/etc]"
109 "[+sh_open()?Paths matching \b/etc/\b* are changed to "
112 "[+SEE ALSO?\bksh\b(1), \bregress\b(1), \brt\b(1)]"
115 static const char* regress_options
[] =
125 void sh_regress_init(Shell_t
* shp
)
127 static Regress_t state
;
129 shp
->regress
= &state
;
133 * regress info trace output
136 void sh_regress(unsigned int index
, const char* intercept
, const char* info
, unsigned int line
, const char* file
)
141 if (index
>= 1 && index
<= elementsof(regress_options
))
142 name
= (char*)regress_options
[index
];
144 sfsprintf(name
= buf
, sizeof(buf
), "%u", index
);
145 sfprintf(sfstderr
, REGRESS_HEADER
"%s:%s:%s\n", name
, intercept
, fmtesc(info
));
152 static gid_t intercept_sgid
= 0;
153 static gid_t intercept_egid
= -1;
154 static gid_t intercept_rgid
= -1;
158 if (intercept_rgid
== -1)
159 intercept_rgid
= getgid();
160 if (sh_isregress(REGRESS_egid
))
162 TRACE(egid
, "getegid", ("%s", intercept_egid
== intercept_rgid
? "egid==rgid" : "egid!=rgid"));
163 return intercept_egid
;
165 return intercept_rgid
;
168 int setgid(gid_t gid
)
170 if (intercept_rgid
== -1)
171 intercept_rgid
= getgid();
172 if (sh_isregress(REGRESS_egid
))
174 if (gid
!= intercept_rgid
&& gid
!= intercept_sgid
)
176 TRACE(egid
, "setgid", ("%s", "EPERM"));
180 intercept_egid
= gid
;
181 TRACE(egid
, "setgid", ("%s", intercept_egid
== intercept_rgid
? "egid==rgid" : "egid!=rgid"));
183 else if (gid
!= intercept_rgid
)
195 static uid_t intercept_suid
= 0;
196 static uid_t intercept_euid
= -1;
197 static uid_t intercept_ruid
= -1;
201 if (intercept_ruid
== -1)
202 intercept_ruid
= getuid();
203 if (sh_isregress(REGRESS_euid
))
205 TRACE(euid
, "geteuid", ("%s", intercept_euid
== intercept_ruid
? "euid==ruid" : "euid!=ruid"));
206 return intercept_euid
;
208 return intercept_ruid
;
211 int setuid(uid_t uid
)
213 if (intercept_ruid
== -1)
214 intercept_ruid
= getuid();
215 if (sh_isregress(REGRESS_euid
))
217 if (uid
!= intercept_ruid
&& uid
!= intercept_suid
)
219 TRACE(euid
, "setuid", ("%s", "EPERM"));
223 intercept_euid
= uid
;
224 TRACE(euid
, "setuid", ("%s", intercept_euid
== intercept_ruid
? "euid==ruid" : "euid!=ruid"));
226 else if (uid
!= intercept_ruid
)
238 static uid_t intercept_p_suid
= 0x7fffffff;
240 uid_t
sh_regress_p_suid(unsigned int line
, const char* file
)
242 REGRESS(p_suid
, "SHOPT_P_SUID", ("%d", intercept_p_suid
));
243 return intercept_p_suid
;
250 static char* intercept_etc
= 0;
252 char* sh_regress_etc(const char* path
, unsigned int line
, const char* file
)
254 REGRESS(etc
, "sh_open", ("%s => %s%s", path
, intercept_etc
, path
+4));
255 return intercept_etc
;
259 * __regress__ builtin
262 int b___regress__(int argc
, char** argv
, void *extra
)
264 register Shell_t
* shp
= ((Shbltin_t
*)extra
)->shp
;
269 switch (n
= optget(argv
, usage
))
272 errormsg(SH_DICT
, ERROR_usage(2), "%s", opt_info
.arg
);
275 errormsg(SH_DICT
, 2, "%s", opt_info
.arg
);
283 if (opt_info
.arg
|| opt_info
.number
)
292 intercept_egid
= intercept_sgid
= (gid_t
)opt_info
.number
;
293 TRACE(egid
, argv
[0], ("%d", intercept_egid
));
296 TRACE(egid
, argv
[0], ("%s", "off"));
301 intercept_euid
= intercept_suid
= (uid_t
)opt_info
.number
;
302 TRACE(euid
, argv
[0], ("%d", intercept_euid
));
305 TRACE(euid
, argv
[0], ("%s", "off"));
310 intercept_p_suid
= (uid_t
)opt_info
.number
;
311 TRACE(p_suid
, argv
[0], ("%d", intercept_p_suid
));
314 TRACE(p_suid
, argv
[0], ("%s", "off"));
317 TRACE(source
, argv
[0], ("%s", sh_isregress(n
) ? "on" : "off"));
322 intercept_etc
= opt_info
.arg
;
323 TRACE(etc
, argv
[0], ("%s", intercept_etc
));
326 TRACE(etc
, argv
[0], ("%s", "off"));
334 if (error_info
.errors
|| *(argv
+ opt_info
.index
))
335 errormsg(SH_DICT
, ERROR_usage(2), "%s", optusage(NiL
));