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

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

◆ main()

int main ( int argc,
char ** argv )

Main function for rsh.

Parameters
argcArgument count
argvArgument vector
Note
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 67 of file rsh.c.

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