C-Menu 0.2.9
A User Interface Toolkit
Loading...
Searching...
No Matches
rsh.c File Reference

restricted shell to run bash as root More...

#include <cm.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <syslog.h>
#include <termios.h>
#include <unistd.h>
Include dependency graph for rsh.c:

Go to the source code of this file.

Macros

#define _GNU_SOURCE
#define HOST   "localhost"

Functions

void ABEND (int e, char const *)
 Abnormal termination - print an error message and exit.
int main (int argc, char **argv)
 Main function for rsh.

Variables

bool F_VERBOSE = false

Detailed Description

restricted shell to run bash as root

Author
Bill Waller Copyright (c) 2025 MIT License billx.nosp@m.wall.nosp@m.er@gm.nosp@m.ail..nosp@m.com
Date
2026-02-09

Definition in file rsh.c.

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Definition at line 10 of file rsh.c.

◆ HOST

#define HOST   "localhost"

Definition at line 29 of file rsh.c.

Function Documentation

◆ ABEND()

void ABEND ( int e,
char const * s )

Abnormal termination - print an error message and exit.

Parameters
eError code
sError message

This function prints the provided error message along with the error code and its corresponding string representation, then exits the program with a failure status.

Definition at line 184 of file rsh.c.

184 {
185 fprintf(stderr, "%s: %d %s\n", s, e, strerror(e));
186 exit(EXIT_FAILURE);
187}

◆ main()

int main ( int argc,
char ** argv )

Main function for rsh.

Parameters
argcArgument count
argvArgument vector

If executed as 'rsh', this program sets the user ID and group ID to 0 (root) and then executes the user's default shell (or /usr/bin/bash if SHELL is not set) with the provided arguments. If no arguments are given, it runs the shell in interactive mode. To work properly, this program must be compiled and set with the setuid bit:

$ sudo -s
cc rsh.c -o rsh
sudo chown root:root rsh
sudo chmod 4755 rsh
exit

to verify proper operation:

$ rsh
$ whoami
root

Definition at line 77 of file rsh.c.

77 {
78 char *cargv[30];
79 char exec_cmd[MAXLEN] = "/usr/bin/bash";
80 char *p;
81 int c;
82 bool ssh_login = false;
83 int status;
84 pid_t pid;
85
86#ifdef RSH_PAM
87 pam_handle_t *pamh = NULL;
88 int retval;
89 char *username = getenv("USER");
90 if (username == NULL) {
91 syslog(LOG_ERR, "USER environment variable not set");
92 fprintf(stderr, "Error: USER environment variable not set\n");
93 return 1;
94 }
95 retval = pam_start("rsh-auth", username, &conv, &pamh);
96 if (retval != PAM_SUCCESS) {
97 syslog(LOG_ERR, "PAM start failed: %s", pam_strerror(pamh, retval));
98 fprintf(stderr, "PAM start failed: %s\n", pam_strerror(pamh, retval));
99 return 1;
100 }
101
102 // Authenticate the user using PAM. The configuration for this PAM service should
103 // be set to allow passwordless authentication, for example by using pam_permit.so.
104 // You can create a PAM configuration file named /etc/pam.d/pam_nopass with the
105 // following content:
106 //
107 // /etc/pam.d/pam_nopass:
108 // auth required pam_permit.so
109 //
110 //
111 retval = pam_authenticate(pamh, 0);
112 if (retval == PAM_SUCCESS) {
113 syslog(LOG_AUTH, "Authentication succeeded for user '%s': %s", username, pam_strerror(pamh, retval));
114 } else {
115 syslog(LOG_AUTH, "Authentication failed for user '%s': %s", username, pam_strerror(pamh, retval));
116 fprintf(stderr, "Failure: Authentication failed: %s\n", pam_strerror(pamh, retval));
117 }
118
119 // It's a wrap
120 pam_end(pamh, retval);
121
122 if (retval != PAM_SUCCESS) {
123 fprintf(stderr, "PAM authentication failed: %s\n", pam_strerror(pamh, retval));
124 exit(EXIT_FAILURE);
125 }
126
127#endif
128 if ((p = getenv("SHELL")))
129 strncpy(exec_cmd, p, MAXLEN - 1);
130 cargv[0] = strdup(exec_cmd);
131 c = 1;
132 if (argc > 0) {
133 for (int i = 1; i < argc; i++) {
134 if (strcmp(argv[i], "-i") == 0) {
135 cargv[c++] = strdup("-i");
136 } else if (strcmp(argv[i], "-D1") == 0 && ssh_login) {
137 fprintf(stderr, "SSH authentication succeeded\n");
138 } else {
139 cargv[c++] = strdup(argv[i]);
140 }
141 }
142 }
143 cargv[c] = nullptr;
144 pid = fork();
145 switch (pid) {
146 case -1:
147 ABEND(EXIT_FAILURE, "fork() fatal error");
148 break;
149 case 0: // Child
150 if (argv[0] && strstr(argv[0], "rsh")) {
151 if (setuid(0) || setgid(0))
152 ABEND(EXIT_FAILURE, "setuid(0) fatal error");
153 struct rlimit rl;
154 getrlimit(RLIMIT_FSIZE, &rl);
155 rl.rlim_cur = RLIM_INFINITY;
156 rl.rlim_max = RLIM_INFINITY;
157 setrlimit(RLIMIT_FSIZE, &rl);
158 }
159 execvp(exec_cmd, cargv);
160 ABEND(EXIT_FAILURE, "execvp() fatal error");
161 break;
162 default: // Parent
163 waitpid(pid, &status, 0);
164 for (int i = 0; i < c; i++)
165 free(cargv[i]);
166#ifdef F_VERBOSE
167 if (WIFEXITED(status)) {
168 rc = WEXITSTATUS(status);
169 if (rc != 0)
170 ABEND(rc, "Child process exited");
171 } else {
172 if (WIFSIGNALED(status)) {
173 rc = WTERMSIG(status);
174 ABEND(rc, "Child process terminated by signal");
175 } else
176 ABEND(EXIT_FAILURE, "Child process terminated abnormally");
177 }
178#endif
179 break;
180 }
181 exit(EXIT_SUCCESS);
182}
void ABEND(int e, char const *)
Abnormal termination - print an error message and exit.
Definition rsh.c:184
#define MAXLEN
Definition curskeys.c:15

References ABEND().

Here is the call graph for this function:

Variable Documentation

◆ F_VERBOSE

bool F_VERBOSE = false

Definition at line 37 of file rsh.c.