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 <libssh/libssh.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.

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.

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 159 of file rsh.c.

159 {
160 fprintf(stderr, "%s: %d %s\n", s, e, strerror(e));
161 exit(EXIT_FAILURE);
162}

◆ 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 66 of file rsh.c.

66 {
67 char *cargv[30];
68 char exec_cmd[MAXLEN] = "/usr/bin/bash";
69 char rsh_user[MAXLEN];
70 char *p;
71 int c, a;
72 int rc;
73 int status;
74 pid_t pid;
75#ifdef RSH_SSH
76 ssh_session _ssh_session = ssh_new();
77 if (_ssh_session == nullptr)
78 exit(EXIT_FAILURE);
79 // "$HOME"/.ssh/authorized_keys
80 ssh_options_set(_ssh_session, SSH_OPTIONS_HOST, "localhost");
81 if ((rc = ssh_connect(_ssh_session)) != SSH_OK) {
82 fprintf(stderr, "Error: %s\n", ssh_get_error(_ssh_session));
83 ssh_free(_ssh_session);
84 exit(EXIT_FAILURE);
85 }
86 // Authenticate using public key
87 if (ssh_userauth_publickey_auto(_ssh_session, NULL, NULL) !=
88 SSH_AUTH_SUCCESS) {
89 fprintf(stderr, "SSH Public key auth failed: %s\n",
90 ssh_get_error(_ssh_session));
91 syslog(LOG_ERR, "SSH Error: %s", ssh_get_error(_ssh_session));
92 exit(EXIT_FAILURE);
93 }
94 ssh_disconnect(_ssh_session);
95 ssh_free(_ssh_session);
96#endif
97#ifdef RSH_LOG
98 char ttyname[MAXLEN];
99 p = getenv("USER");
100 strncpy(rsh_user, p ? p : "unknown", sizeof(rsh_user));
101 openlog("rsh", LOG_PID | LOG_CONS, LOG_AUTH);
102 if (ttyname_r(STDERR_FILENO, ttyname, sizeof(ttyname)) == 0)
103 syslog(LOG_INFO, "rsh started by user '%s' on terminal '%s'", rsh_user,
104 ttyname);
105 closelog();
106#endif
107 if ((p = getenv("SHELL")))
108 strncpy(exec_cmd, p, MAXLEN - 1);
109 cargv[0] = strdup(exec_cmd);
110 c = 1;
111 a = 1;
112 if (argc == 1)
113 cargv[c++] = "-i";
114 while (a < argc)
115 cargv[c++] = strdup(argv[a++]);
116 cargv[c] = (char *)'\0';
117 pid = fork();
118 switch (pid) {
119 case -1:
120 ABEND(EXIT_FAILURE, "fork() fatal error");
121 break;
122 case 0: // Child
123 if (argv[0] && strstr(argv[0], "rsh")) {
124 if (setuid(0) || setgid(0))
125 ABEND(EXIT_FAILURE, "setuid(0) fatal error");
126 struct rlimit rl;
127 getrlimit(RLIMIT_FSIZE, &rl);
128 rl.rlim_cur = RLIM_INFINITY;
129 rl.rlim_max = RLIM_INFINITY;
130 setrlimit(RLIMIT_FSIZE, &rl);
131 }
132 execvp(exec_cmd, cargv);
133 ABEND(EXIT_FAILURE, "execvp() fatal error");
134 break;
135 default: // Parent
136
137 waitpid(pid, &status, 0);
138 if (f_verbose) {
139 if (WIFEXITED(status)) {
140 rc = WEXITSTATUS(status);
141 if (rc != 0)
142 ABEND(rc, "Child process exited");
143 } else {
144 if (WIFSIGNALED(status)) {
145 rc = WTERMSIG(status);
146 ABEND(rc, "Child process terminated by signal");
147 } else
148 ABEND(EXIT_FAILURE, "Child process terminated abnormally");
149 }
150 }
151 break;
152 }
153 openlog("rsh", LOG_PID | LOG_CONS, LOG_AUTH);
154 syslog(LOG_INFO, "rsh exited by user '%s'", rsh_user);
155 closelog();
156 exit(EXIT_SUCCESS);
157}
void ABEND(int e, char const *)
Abnormal termination - print an error message and exit.
Definition rsh.c:159
bool f_verbose
Definition rsh.c:32
#define MAXLEN
Definition curskeys.c:15

References ABEND(), and f_verbose.

Here is the call graph for this function:

Variable Documentation

◆ f_verbose

bool f_verbose = false

Definition at line 32 of file rsh.c.

Referenced by main().