134f9b3eeSRoland Mainz /***********************************************************************
234f9b3eeSRoland Mainz * *
334f9b3eeSRoland Mainz * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
534f9b3eeSRoland Mainz * and is licensed under the *
634f9b3eeSRoland Mainz * Common Public License, Version 1.0 *
734f9b3eeSRoland Mainz * by AT&T Intellectual Property *
834f9b3eeSRoland Mainz * *
934f9b3eeSRoland Mainz * A copy of the License is available at *
1034f9b3eeSRoland Mainz * http://www.opensource.org/licenses/cpl1.0.txt *
1134f9b3eeSRoland Mainz * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1234f9b3eeSRoland Mainz * *
1334f9b3eeSRoland Mainz * Information and Software Systems Research *
1434f9b3eeSRoland Mainz * AT&T Research *
1534f9b3eeSRoland Mainz * Florham Park NJ *
1634f9b3eeSRoland Mainz * *
1734f9b3eeSRoland Mainz * David Korn <dgk@research.att.com> *
1834f9b3eeSRoland Mainz * *
1934f9b3eeSRoland Mainz ***********************************************************************/
2034f9b3eeSRoland Mainz #pragma prototyped
2134f9b3eeSRoland Mainz /*
2234f9b3eeSRoland Mainz * regression test intercept control
2334f9b3eeSRoland Mainz * enable with SHOPT_REGRESS==1 in Makefile
2434f9b3eeSRoland Mainz * not for production use
2534f9b3eeSRoland Mainz * see --man for details
2634f9b3eeSRoland Mainz * all string constants inline here instead of in data/...
2734f9b3eeSRoland Mainz *
2834f9b3eeSRoland Mainz * David Korn
2934f9b3eeSRoland Mainz * at&t research
3034f9b3eeSRoland Mainz */
3134f9b3eeSRoland Mainz
3234f9b3eeSRoland Mainz #include "defs.h"
3334f9b3eeSRoland Mainz
3434f9b3eeSRoland Mainz #if SHOPT_REGRESS
3534f9b3eeSRoland Mainz
3634f9b3eeSRoland Mainz #include <error.h>
3734f9b3eeSRoland Mainz #include <ls.h>
3834f9b3eeSRoland Mainz #include "io.h"
3934f9b3eeSRoland Mainz #include "builtins.h"
4034f9b3eeSRoland Mainz #include <tmx.h>
4134f9b3eeSRoland Mainz
4234f9b3eeSRoland Mainz #define REGRESS_HEADER "ksh:REGRESS:"
4334f9b3eeSRoland Mainz
4434f9b3eeSRoland Mainz #define TRACE(r,i,f) sh_regress(REGRESS_##r, i, sfprints f, __LINE__, __FILE__)
4534f9b3eeSRoland Mainz
4634f9b3eeSRoland Mainz static const char usage[] =
4734f9b3eeSRoland Mainz "[-1p0?\n@(#)$Id: __regress__ (AT&T Research) 2009-03-29 $\n]"
4834f9b3eeSRoland Mainz USAGE_LICENSE
4934f9b3eeSRoland Mainz "[+NAME?__regress__ - shell regression test intercept control]"
5034f9b3eeSRoland Mainz "[+DESCRIPTION?\b__regress__\b controls the regression test intercepts "
5134f9b3eeSRoland Mainz "for shells compiled with SHOPT_REGRESS==1. Shells compiled this way are "
5234f9b3eeSRoland Mainz "for testing only. In addition to \b__regress__\b and the \b--regress\b "
5334f9b3eeSRoland Mainz "command line option, these shells may contain system library function "
5434f9b3eeSRoland Mainz "intercepts that behave different from the native counterparts.]"
5534f9b3eeSRoland Mainz "[+?Each option controls a different test and possibly a different set "
5634f9b3eeSRoland Mainz "of intercepts. The options are interpreted \bdd\b(1) style -- '-' or "
5734f9b3eeSRoland Mainz "'--' prefix not required. This simplifies the specification of the "
5834f9b3eeSRoland Mainz "command line \b--regress\b=\avalue\a option, where \avalue\a is passed "
5934f9b3eeSRoland Mainz "as an option to the \b__regress__\b builtin. Typically regression test "
6034f9b3eeSRoland Mainz "intercepts are enabled with one or more command line \b--regress\b "
6134f9b3eeSRoland Mainz "options, with optional specific calls to \b__regress__\b in test "
6234f9b3eeSRoland Mainz "scripts to enable/disable intercepts as the test progresses.]"
6334f9b3eeSRoland Mainz "[+?Each enabled intercept may result in trace lines of the form \b" REGRESS_HEADER
6434f9b3eeSRoland Mainz "\aoption\a:\aintercept\a:\ainfo\a on the standard error, where "
6534f9b3eeSRoland Mainz "\aoption\a is one of the options below, \aintercept\a is the name of "
6634f9b3eeSRoland Mainz "the specific intercept for \aoption\a, and \ainfo\a is \aoption\a "
6734f9b3eeSRoland Mainz "specific information. Unless noted otherwise, one regression test trace "
6834f9b3eeSRoland Mainz "line is produced each time an enabled intercept is called.]"
6934f9b3eeSRoland Mainz "[101:egid?The intercept effective gid is set to \aoriginal-egid\a. The "
7034f9b3eeSRoland Mainz "effective gid of the underlying system process is not affected. The "
7134f9b3eeSRoland Mainz "trace line info is either \begid==rgid\b or \begid!=rgid\b. The "
7234f9b3eeSRoland Mainz "intercepts are:]#?[original-egid:=1]"
7334f9b3eeSRoland Mainz "{"
7434f9b3eeSRoland Mainz "[+getegid()?The intercept effecive gid is returned. The "
7534f9b3eeSRoland Mainz "\bsetgid\b() intercept may change this between the real gid and "
7634f9b3eeSRoland Mainz "\aoriginal-egid\a.]"
7734f9b3eeSRoland Mainz "[+setgid(gid)?Sets the intercept effective gid to \agid\a. "
7834f9b3eeSRoland Mainz "Fails if \agid\a is neither the real gid nor "
7934f9b3eeSRoland Mainz "\aoriginal-egid\a.]"
8034f9b3eeSRoland Mainz "}"
8134f9b3eeSRoland Mainz "[102:euid?The intercept effective uid is set to \aoriginal-euid\a. The "
8234f9b3eeSRoland Mainz "effective uid of the underlying system process is not affected. The "
8334f9b3eeSRoland Mainz "trace line info is either \beuid==ruid\b or \beuid!=ruid\b. The "
8434f9b3eeSRoland Mainz "intercepts are:]#?[original-euid:=1]"
8534f9b3eeSRoland Mainz "{"
8634f9b3eeSRoland Mainz "[+geteuid()?The intercept effecive uid is returned. The "
8734f9b3eeSRoland Mainz "\bsetuid\b() intercept may change this between the real uid and "
8834f9b3eeSRoland Mainz "\aoriginal-euid\a.]"
8934f9b3eeSRoland Mainz "[+setuid(uid)?Sets the intercept effective uid to \auid\a. "
9034f9b3eeSRoland Mainz "Fails if \auid\a is neither the real uid nor "
9134f9b3eeSRoland Mainz "\aoriginal-euid\a.]"
9234f9b3eeSRoland Mainz "}"
9334f9b3eeSRoland Mainz "[103:p_suid?Specifies a value for SHOPT_P_SUID. Effective uids greater "
9434f9b3eeSRoland Mainz "than the non-privileged-uid disable the priveleged mode. The intercepts "
9534f9b3eeSRoland Mainz "are:]#?[non-privileged-uid:=1]"
9634f9b3eeSRoland Mainz "{"
9734f9b3eeSRoland Mainz "[+SHOPT_P_SUID?The SHOPT_P_SUID macro value is overridden by "
9834f9b3eeSRoland Mainz "\bp_suid\b. A trace line is output for each SHOPT_P_SUID "
9934f9b3eeSRoland Mainz "access.]"
10034f9b3eeSRoland Mainz "}"
10134f9b3eeSRoland Mainz "[104:source?The intercepts are:]"
10234f9b3eeSRoland Mainz "{"
10334f9b3eeSRoland Mainz "[+sh_source()?The trace line info is the path of the script "
10434f9b3eeSRoland Mainz "being sourced. Used to trace shell startup scripts.]"
10534f9b3eeSRoland Mainz "}"
10634f9b3eeSRoland Mainz "[105:etc?Map file paths matching \b/etc/\b* to \aetc-dir\a/*. The "
10734f9b3eeSRoland Mainz "intercepts are:]:[etc-dir:=/etc]"
10834f9b3eeSRoland Mainz "{"
10934f9b3eeSRoland Mainz "[+sh_open()?Paths matching \b/etc/\b* are changed to "
11034f9b3eeSRoland Mainz "\aetc-dir\a/*.]"
11134f9b3eeSRoland Mainz "}"
11234f9b3eeSRoland Mainz "[+SEE ALSO?\bksh\b(1), \bregress\b(1), \brt\b(1)]"
11334f9b3eeSRoland Mainz ;
11434f9b3eeSRoland Mainz
11534f9b3eeSRoland Mainz static const char* regress_options[] =
11634f9b3eeSRoland Mainz {
11734f9b3eeSRoland Mainz "ERROR",
11834f9b3eeSRoland Mainz "egid",
11934f9b3eeSRoland Mainz "euid",
12034f9b3eeSRoland Mainz "p_suid",
12134f9b3eeSRoland Mainz "source",
12234f9b3eeSRoland Mainz "etc",
12334f9b3eeSRoland Mainz };
12434f9b3eeSRoland Mainz
sh_regress_init(Shell_t * shp)12534f9b3eeSRoland Mainz void sh_regress_init(Shell_t* shp)
12634f9b3eeSRoland Mainz {
12734f9b3eeSRoland Mainz static Regress_t state;
12834f9b3eeSRoland Mainz
12934f9b3eeSRoland Mainz shp->regress = &state;
13034f9b3eeSRoland Mainz }
13134f9b3eeSRoland Mainz
13234f9b3eeSRoland Mainz /*
13334f9b3eeSRoland Mainz * regress info trace output
13434f9b3eeSRoland Mainz */
13534f9b3eeSRoland Mainz
sh_regress(unsigned int index,const char * intercept,const char * info,unsigned int line,const char * file)13634f9b3eeSRoland Mainz void sh_regress(unsigned int index, const char* intercept, const char* info, unsigned int line, const char* file)
13734f9b3eeSRoland Mainz {
13834f9b3eeSRoland Mainz char* name;
13934f9b3eeSRoland Mainz char buf[16];
14034f9b3eeSRoland Mainz
14134f9b3eeSRoland Mainz if (index >= 1 && index <= elementsof(regress_options))
14234f9b3eeSRoland Mainz name = (char*)regress_options[index];
14334f9b3eeSRoland Mainz else
14434f9b3eeSRoland Mainz sfsprintf(name = buf, sizeof(buf), "%u", index);
14534f9b3eeSRoland Mainz sfprintf(sfstderr, REGRESS_HEADER "%s:%s:%s\n", name, intercept, fmtesc(info));
14634f9b3eeSRoland Mainz }
14734f9b3eeSRoland Mainz
14834f9b3eeSRoland Mainz /*
14934f9b3eeSRoland Mainz * egid intercepts
15034f9b3eeSRoland Mainz */
15134f9b3eeSRoland Mainz
15234f9b3eeSRoland Mainz static gid_t intercept_sgid = 0;
15334f9b3eeSRoland Mainz static gid_t intercept_egid = -1;
15434f9b3eeSRoland Mainz static gid_t intercept_rgid = -1;
15534f9b3eeSRoland Mainz
getegid(void)15634f9b3eeSRoland Mainz gid_t getegid(void)
15734f9b3eeSRoland Mainz {
15834f9b3eeSRoland Mainz if (intercept_rgid == -1)
15934f9b3eeSRoland Mainz intercept_rgid = getgid();
16034f9b3eeSRoland Mainz if (sh_isregress(REGRESS_egid))
16134f9b3eeSRoland Mainz {
16234f9b3eeSRoland Mainz TRACE(egid, "getegid", ("%s", intercept_egid == intercept_rgid ? "egid==rgid" : "egid!=rgid"));
16334f9b3eeSRoland Mainz return intercept_egid;
16434f9b3eeSRoland Mainz }
16534f9b3eeSRoland Mainz return intercept_rgid;
16634f9b3eeSRoland Mainz }
16734f9b3eeSRoland Mainz
setgid(gid_t gid)16834f9b3eeSRoland Mainz int setgid(gid_t gid)
16934f9b3eeSRoland Mainz {
17034f9b3eeSRoland Mainz if (intercept_rgid == -1)
17134f9b3eeSRoland Mainz intercept_rgid = getgid();
17234f9b3eeSRoland Mainz if (sh_isregress(REGRESS_egid))
17334f9b3eeSRoland Mainz {
17434f9b3eeSRoland Mainz if (gid != intercept_rgid && gid != intercept_sgid)
17534f9b3eeSRoland Mainz {
17634f9b3eeSRoland Mainz TRACE(egid, "setgid", ("%s", "EPERM"));
17734f9b3eeSRoland Mainz errno = EPERM;
17834f9b3eeSRoland Mainz return -1;
17934f9b3eeSRoland Mainz }
18034f9b3eeSRoland Mainz intercept_egid = gid;
18134f9b3eeSRoland Mainz TRACE(egid, "setgid", ("%s", intercept_egid == intercept_rgid ? "egid==rgid" : "egid!=rgid"));
18234f9b3eeSRoland Mainz }
18334f9b3eeSRoland Mainz else if (gid != intercept_rgid)
18434f9b3eeSRoland Mainz {
18534f9b3eeSRoland Mainz errno = EPERM;
18634f9b3eeSRoland Mainz return -1;
18734f9b3eeSRoland Mainz }
18834f9b3eeSRoland Mainz return 0;
18934f9b3eeSRoland Mainz }
19034f9b3eeSRoland Mainz
19134f9b3eeSRoland Mainz /*
19234f9b3eeSRoland Mainz * euid intercepts
19334f9b3eeSRoland Mainz */
19434f9b3eeSRoland Mainz
19534f9b3eeSRoland Mainz static uid_t intercept_suid = 0;
19634f9b3eeSRoland Mainz static uid_t intercept_euid = -1;
19734f9b3eeSRoland Mainz static uid_t intercept_ruid = -1;
19834f9b3eeSRoland Mainz
geteuid(void)19934f9b3eeSRoland Mainz uid_t geteuid(void)
20034f9b3eeSRoland Mainz {
20134f9b3eeSRoland Mainz if (intercept_ruid == -1)
20234f9b3eeSRoland Mainz intercept_ruid = getuid();
20334f9b3eeSRoland Mainz if (sh_isregress(REGRESS_euid))
20434f9b3eeSRoland Mainz {
20534f9b3eeSRoland Mainz TRACE(euid, "geteuid", ("%s", intercept_euid == intercept_ruid ? "euid==ruid" : "euid!=ruid"));
20634f9b3eeSRoland Mainz return intercept_euid;
20734f9b3eeSRoland Mainz }
20834f9b3eeSRoland Mainz return intercept_ruid;
20934f9b3eeSRoland Mainz }
21034f9b3eeSRoland Mainz
setuid(uid_t uid)21134f9b3eeSRoland Mainz int setuid(uid_t uid)
21234f9b3eeSRoland Mainz {
21334f9b3eeSRoland Mainz if (intercept_ruid == -1)
21434f9b3eeSRoland Mainz intercept_ruid = getuid();
21534f9b3eeSRoland Mainz if (sh_isregress(REGRESS_euid))
21634f9b3eeSRoland Mainz {
21734f9b3eeSRoland Mainz if (uid != intercept_ruid && uid != intercept_suid)
21834f9b3eeSRoland Mainz {
21934f9b3eeSRoland Mainz TRACE(euid, "setuid", ("%s", "EPERM"));
22034f9b3eeSRoland Mainz errno = EPERM;
22134f9b3eeSRoland Mainz return -1;
22234f9b3eeSRoland Mainz }
22334f9b3eeSRoland Mainz intercept_euid = uid;
22434f9b3eeSRoland Mainz TRACE(euid, "setuid", ("%s", intercept_euid == intercept_ruid ? "euid==ruid" : "euid!=ruid"));
22534f9b3eeSRoland Mainz }
22634f9b3eeSRoland Mainz else if (uid != intercept_ruid)
22734f9b3eeSRoland Mainz {
22834f9b3eeSRoland Mainz errno = EPERM;
22934f9b3eeSRoland Mainz return -1;
23034f9b3eeSRoland Mainz }
23134f9b3eeSRoland Mainz return 0;
23234f9b3eeSRoland Mainz }
23334f9b3eeSRoland Mainz
23434f9b3eeSRoland Mainz /*
23534f9b3eeSRoland Mainz * p_suid intercept
23634f9b3eeSRoland Mainz */
23734f9b3eeSRoland Mainz
23834f9b3eeSRoland Mainz static uid_t intercept_p_suid = 0x7fffffff;
23934f9b3eeSRoland Mainz
sh_regress_p_suid(unsigned int line,const char * file)24034f9b3eeSRoland Mainz uid_t sh_regress_p_suid(unsigned int line, const char* file)
24134f9b3eeSRoland Mainz {
24234f9b3eeSRoland Mainz REGRESS(p_suid, "SHOPT_P_SUID", ("%d", intercept_p_suid));
24334f9b3eeSRoland Mainz return intercept_p_suid;
24434f9b3eeSRoland Mainz }
24534f9b3eeSRoland Mainz
24634f9b3eeSRoland Mainz /*
24734f9b3eeSRoland Mainz * p_suid intercept
24834f9b3eeSRoland Mainz */
24934f9b3eeSRoland Mainz
25034f9b3eeSRoland Mainz static char* intercept_etc = 0;
25134f9b3eeSRoland Mainz
sh_regress_etc(const char * path,unsigned int line,const char * file)25234f9b3eeSRoland Mainz char* sh_regress_etc(const char* path, unsigned int line, const char* file)
25334f9b3eeSRoland Mainz {
25434f9b3eeSRoland Mainz REGRESS(etc, "sh_open", ("%s => %s%s", path, intercept_etc, path+4));
25534f9b3eeSRoland Mainz return intercept_etc;
25634f9b3eeSRoland Mainz }
25734f9b3eeSRoland Mainz
25834f9b3eeSRoland Mainz /*
25934f9b3eeSRoland Mainz * __regress__ builtin
26034f9b3eeSRoland Mainz */
26134f9b3eeSRoland Mainz
b___regress__(int argc,char ** argv,void * extra)26234f9b3eeSRoland Mainz int b___regress__(int argc, char** argv, void *extra)
26334f9b3eeSRoland Mainz {
26434f9b3eeSRoland Mainz register Shell_t* shp = ((Shbltin_t*)extra)->shp;
26534f9b3eeSRoland Mainz int n;
26634f9b3eeSRoland Mainz
26734f9b3eeSRoland Mainz for (;;)
26834f9b3eeSRoland Mainz {
26934f9b3eeSRoland Mainz switch (n = optget(argv, usage))
27034f9b3eeSRoland Mainz {
27134f9b3eeSRoland Mainz case '?':
27234f9b3eeSRoland Mainz errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
27334f9b3eeSRoland Mainz break;
27434f9b3eeSRoland Mainz case ':':
27534f9b3eeSRoland Mainz errormsg(SH_DICT, 2, "%s", opt_info.arg);
27634f9b3eeSRoland Mainz break;
27734f9b3eeSRoland Mainz case 0:
27834f9b3eeSRoland Mainz break;
27934f9b3eeSRoland Mainz default:
28034f9b3eeSRoland Mainz if (n < -100)
28134f9b3eeSRoland Mainz {
28234f9b3eeSRoland Mainz n = -(n + 100);
28334f9b3eeSRoland Mainz if (opt_info.arg || opt_info.number)
28434f9b3eeSRoland Mainz sh_onregress(n);
28534f9b3eeSRoland Mainz else
28634f9b3eeSRoland Mainz sh_offregress(n);
28734f9b3eeSRoland Mainz switch (n)
28834f9b3eeSRoland Mainz {
28934f9b3eeSRoland Mainz case REGRESS_egid:
29034f9b3eeSRoland Mainz if (sh_isregress(n))
29134f9b3eeSRoland Mainz {
29234f9b3eeSRoland Mainz intercept_egid = intercept_sgid = (gid_t)opt_info.number;
29334f9b3eeSRoland Mainz TRACE(egid, argv[0], ("%d", intercept_egid));
29434f9b3eeSRoland Mainz }
29534f9b3eeSRoland Mainz else
29634f9b3eeSRoland Mainz TRACE(egid, argv[0], ("%s", "off"));
29734f9b3eeSRoland Mainz break;
29834f9b3eeSRoland Mainz case REGRESS_euid:
29934f9b3eeSRoland Mainz if (sh_isregress(n))
30034f9b3eeSRoland Mainz {
30134f9b3eeSRoland Mainz intercept_euid = intercept_suid = (uid_t)opt_info.number;
30234f9b3eeSRoland Mainz TRACE(euid, argv[0], ("%d", intercept_euid));
30334f9b3eeSRoland Mainz }
30434f9b3eeSRoland Mainz else
30534f9b3eeSRoland Mainz TRACE(euid, argv[0], ("%s", "off"));
30634f9b3eeSRoland Mainz break;
30734f9b3eeSRoland Mainz case REGRESS_p_suid:
30834f9b3eeSRoland Mainz if (sh_isregress(n))
30934f9b3eeSRoland Mainz {
31034f9b3eeSRoland Mainz intercept_p_suid = (uid_t)opt_info.number;
31134f9b3eeSRoland Mainz TRACE(p_suid, argv[0], ("%d", intercept_p_suid));
31234f9b3eeSRoland Mainz }
31334f9b3eeSRoland Mainz else
31434f9b3eeSRoland Mainz TRACE(p_suid, argv[0], ("%s", "off"));
31534f9b3eeSRoland Mainz break;
31634f9b3eeSRoland Mainz case REGRESS_source:
31734f9b3eeSRoland Mainz TRACE(source, argv[0], ("%s", sh_isregress(n) ? "on" : "off"));
31834f9b3eeSRoland Mainz break;
31934f9b3eeSRoland Mainz case REGRESS_etc:
32034f9b3eeSRoland Mainz if (sh_isregress(n))
32134f9b3eeSRoland Mainz {
32234f9b3eeSRoland Mainz intercept_etc = opt_info.arg;
32334f9b3eeSRoland Mainz TRACE(etc, argv[0], ("%s", intercept_etc));
32434f9b3eeSRoland Mainz }
32534f9b3eeSRoland Mainz else
32634f9b3eeSRoland Mainz TRACE(etc, argv[0], ("%s", "off"));
32734f9b3eeSRoland Mainz break;
32834f9b3eeSRoland Mainz }
32934f9b3eeSRoland Mainz }
33034f9b3eeSRoland Mainz continue;
33134f9b3eeSRoland Mainz }
33234f9b3eeSRoland Mainz break;
33334f9b3eeSRoland Mainz }
33434f9b3eeSRoland Mainz if (error_info.errors || *(argv + opt_info.index))
33534f9b3eeSRoland Mainz errormsg(SH_DICT, ERROR_usage(2), "%s", optusage(NiL));
33634f9b3eeSRoland Mainz return 0;
33734f9b3eeSRoland Mainz }
33834f9b3eeSRoland Mainz
33934f9b3eeSRoland Mainz #else
34034f9b3eeSRoland Mainz
34134f9b3eeSRoland Mainz NoN(regress)
34234f9b3eeSRoland Mainz
34334f9b3eeSRoland Mainz #endif
344