1 /* vi: set sw=4 ts=4: */
2 /*
3  * issue.c: issue printing code
4  *
5  * Copyright (C) 2003 Bastian Blank <waldi@tuxbox.org>
6  *
7  * Optimize and correcting OCRNL by Vladimir Oleynik <dzo@simtreas.ru>
8  *
9  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10  */
11 #include "libbb.h"
12 /* After libbb.h, since it needs sys/types.h on some systems */
13 #include <sys/utsname.h>
14 
15 #define LOGIN " login: "
16 
17 static const char fmtstr_d[] ALIGN1 = "%A, %d %B %Y";
18 
print_login_issue(const char * issue_file,const char * tty)19 void FAST_FUNC print_login_issue(const char *issue_file, const char *tty)
20 {
21 	FILE *fp;
22 	int c;
23 	char buf[256+1];
24 	const char *outbuf;
25 	time_t t;
26 	struct utsname uts;
27 
28 	time(&t);
29 	uname(&uts);
30 
31 	puts("\r");  /* start a new line */
32 
33 	fp = fopen_for_read(issue_file);
34 	if (!fp)
35 		return;
36 	while ((c = fgetc(fp)) != EOF) {
37 		outbuf = buf;
38 		buf[0] = c;
39 		buf[1] = '\0';
40 		if (c == '\n') {
41 			buf[1] = '\r';
42 			buf[2] = '\0';
43 		}
44 		if (c == '\\' || c == '%') {
45 			c = fgetc(fp);
46 			switch (c) {
47 //From getty manpage (* - supported by us)
48 //========================================
49 //4 or 4{interface}
50 //  Insert the IPv4 address of the network interface (example: \4{eth0}).
51 //  If the interface argument is not specified, then select the first
52 //  fully configured (UP, non-LOOPBACK, RUNNING) interface.
53 //6 or 6{interface} -- The same as \4 but for IPv6.
54 //b -- Insert the baudrate of the current line.
55 //*d -- Insert the current date.
56 //*t -- Insert the current time.
57 //e or e{name}
58 //  Translate the human-readable name to an escape sequence and insert it
59 //  (for example: \e{red}Alert text.\e{reset}).  If the name argument
60 //  is not specified, then insert \033. The currently supported names are:
61 //  black, blink, blue, bold, brown, cyan, darkgray, gray, green, halfbright,
62 //  lightblue, lightcyan, lightgray, lightgreen, lightmagenta, lightred,
63 //  magenta, red, reset, reverse, and yellow. Unknown names are ignored.
64 //*s
65 //  Insert the system name (the name of the operating system - `uname -s`)
66 //*S or S{VARIABLE}
67 //  Insert the VARIABLE data from /etc/os-release.
68 //  If the VARIABLE argument is not specified, use PRETTY_NAME.
69 //  If PRETTY_NAME is not in /etc/os-release, \S is the same as \s.
70 //*l -- Insert the name of the current tty line.
71 //*m -- Insert the architecture identifier of the machine: `uname -m`.
72 //*n -- Insert the nodename of the machine: `uname -n`.
73 //*o -- Insert the NIS domainname of the machine.  Same as `hostname -d'.
74 //*O -- Insert the DNS domainname of the machine.
75 //*r -- Insert the release number of the OS: `uname -r`.
76 //u -- Insert the number of current users logged in.
77 //U -- Insert the string "1 user" or "N users" (current users logged in).
78 //*v -- Insert the version of the OS, e.g. the build-date etc: `uname -v`.
79 //We also implement:
80 //*D -- same as \O "DNS domainname"
81 //*h -- same as \n "nodename"
82 
83 			case 'S':
84 				/* minimal implementation, not reading /etc/os-release */
85 				/*FALLTHROUGH*/
86 			case 's':
87 				outbuf = uts.sysname;
88 				break;
89 			case 'n':
90 			case 'h':
91 				outbuf = uts.nodename;
92 				break;
93 			case 'r':
94 				outbuf = uts.release;
95 				break;
96 			case 'v':
97 				outbuf = uts.version;
98 				break;
99 			case 'm':
100 				outbuf = uts.machine;
101 				break;
102 /* The field domainname of struct utsname is Linux specific. */
103 #if defined(__linux__)
104 			case 'D':
105 			case 'o':
106 			case 'O':
107 				outbuf = uts.domainname;
108 				break;
109 #endif
110 			case 'd':
111 				strftime(buf, sizeof(buf), fmtstr_d, localtime(&t));
112 				break;
113 			case 't':
114 				strftime_HHMMSS(buf, sizeof(buf), &t);
115 				break;
116 			case 'l':
117 				outbuf = tty;
118 				break;
119 			default:
120 				buf[0] = c;
121 			}
122 		}
123 		fputs_stdout(outbuf);
124 	}
125 	fclose(fp);
126 	fflush_all();
127 }
128 
print_login_prompt(void)129 void FAST_FUNC print_login_prompt(void)
130 {
131 	char *hostname = safe_gethostname();
132 
133 	fputs_stdout(hostname);
134 	fputs_stdout(LOGIN);
135 	fflush_all();
136 	free(hostname);
137 }
138 
139 /* Clear dangerous stuff, set PATH */
140 static const char forbid[] ALIGN1 =
141 	"ENV" "\0"
142 	"BASH_ENV" "\0"
143 	"HOME" "\0"
144 	"IFS" "\0"
145 	"SHELL" "\0"
146 	"LD_LIBRARY_PATH" "\0"
147 	"LD_PRELOAD" "\0"
148 	"LD_TRACE_LOADED_OBJECTS" "\0"
149 	"LD_BIND_NOW" "\0"
150 	"LD_AOUT_LIBRARY_PATH" "\0"
151 	"LD_AOUT_PRELOAD" "\0"
152 	"LD_NOWARN" "\0"
153 	"LD_KEEPDIR" "\0";
154 
sanitize_env_if_suid(void)155 int FAST_FUNC sanitize_env_if_suid(void)
156 {
157 	const char *p;
158 
159 	if (getuid() == geteuid())
160 		return 0;
161 
162 	p = forbid;
163 	do {
164 		unsetenv(p);
165 		p += strlen(p) + 1;
166 	} while (*p);
167 	putenv((char*)bb_PATH_root_path);
168 
169 	return 1; /* we indeed were run by different user! */
170 }
171