The Pedigree Project  0.1
sudo/main.c
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <errno.h>
21 #include <pwd.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <termios.h>
29 #include <unistd.h>
30 
31 // Pedigree function, from libpedigree-c
32 extern int pedigree_login(int uid, char *password);
33 
34 int main(int argc, char *argv[])
35 {
36  int iRunShell = 0, error = 0, help = 0, nStart = 0, i = 0;
37  for (i = 1; i < argc; i++)
38  {
39  if (!strcmp(argv[i], "-s"))
40  iRunShell = 1;
41  else if (!strcmp(argv[i], "-h"))
42  help = 1;
43  else if (!nStart)
44  nStart = i;
45  }
46 
47  // If there was an error, or if the help string needs to be printed, do so
48  if (error || help || (!nStart && !iRunShell))
49  {
50  fprintf(stderr, "Usage: sudo [-h] [-s|<command>]\n");
51  fprintf(stderr, "\n");
52  fprintf(stderr, " -s: Access root shell\n");
53  fprintf(stderr, " -h: Show this help text\n");
54  return error;
55  }
56 
57  // Grab the root user's pw structure
58  struct passwd *pw = getpwnam("root");
59  if (!pw)
60  {
61  fprintf(stderr, "sudo: user 'root' doesn't exist!\n");
62  return 1;
63  }
64 
65  // Request the root password
66  char password[256], c;
67  i = 0;
68 
69  struct termios curt;
70  tcgetattr(0, &curt);
71  curt.c_lflag &= ~(ECHO | ICANON);
72  tcsetattr(0, TCSANOW, &curt);
73 
74  printf("[sudo] Enter password: ");
75  fflush(stdout);
76 
77  while (i < 256 && (c = getchar()) != '\n')
78  {
79  if (c == '\b')
80  {
81  if (i > 0)
82  {
83  password[--i] = '\0';
84  printf("\b \b");
85  }
86  }
87  else if (c != '\033')
88  {
89  password[i++] = c;
90  printf("•");
91  }
92  }
93  tcgetattr(0, &curt);
94  curt.c_lflag |= (ECHO | ICANON);
95  tcsetattr(0, TCSANOW, &curt);
96  printf("\n");
97 
98  password[i] = '\0';
99 
100  // Attempt to log in as that user
101  if (pedigree_login(pw->pw_uid, password) != 0)
102  {
103  fprintf(stderr, "sudo: password is incorrect\n");
104  return 1;
105  }
106 
107  // Begin a new session so SIGINT is properly handled here
108  setsid();
109 
110  // We're now running as root, so execute whatever we're supposed to execute
111  if (iRunShell)
112  {
113  // Execute root's shell
114  int pid = fork();
115  if (pid == -1)
116  {
117  fprintf(stderr, "sudo: couldn't fork: %s\n", strerror(errno));
118  exit(errno);
119  }
120  else if (pid == 0)
121  {
122  // Run the command
123  execlp(pw->pw_shell, pw->pw_shell, 0);
124 
125  // Command not found!
126  fprintf(stderr, "sudo: couldn't run shell: %s\n", strerror(errno));
127  exit(errno);
128  }
129  else
130  {
131  // Wait for it to complete
132  int status;
133  waitpid(pid, &status, 0);
134 
135  // Did it exit with a non-zero status?
136  if (status)
137  {
138  // Return error
139  exit(status);
140  }
141  }
142  }
143  else
144  {
145  // Run the command
146  int pid = fork();
147  if (pid == -1)
148  {
149  fprintf(stderr, "sudo: couldn't fork: %s\n", strerror(errno));
150  exit(errno);
151  }
152  else if (pid == 0)
153  {
154  // Run the command
155  execvp(argv[nStart], &argv[nStart]);
156 
157  // Command not found!
158  fprintf(
159  stderr, "sudo: couldn't run command '%s': %s\n", argv[nStart],
160  strerror(errno));
161  exit(errno);
162  }
163  else
164  {
165  // Wait for it to complete
166  int status;
167  waitpid(pid, &status, 0);
168 
169  // Did it exit with a non-zero status?
170  if (status)
171  {
172  // Return error
173  exit(status);
174  }
175  }
176  }
177 
178  // All done!
179  return 0;
180 }