1 // =================================
  2 // Copyright (c) 2022 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 using System.Os;
  9 using System.Security;
 10 using paths;
 11 
 12 void PrintHelp()
 13 {
 14     Console.Out() << "sudo [options] COMMAND [ARGS...]" << endl() << endl();
 15     Console.Out() << "Execute COMMAND as superuser." << endl() << endl();
 16     Console.Out() << "Options:" << endl() << endl();
 17     Console.Out() << "--help | -h" << endl();
 18     Console.Out() << "  Print help and exit." << endl() << endl();
 19 }
 20 
 21 int main(int argcconst char** argv)
 22 {
 23     try
 24     {
 25         List<string> args;
 26         bool programSeen = false;
 27         for (int i = 1; i < argc; ++i;)
 28         {
 29             string arg = argv[i];
 30             if (!programSeen)
 31             {
 32                 if (arg.StartsWith("--"))
 33                 {
 34                     if (arg == "--help")
 35                     {
 36                         PrintHelp();
 37                         return 1;
 38                     }
 39                     else
 40                     {
 41                         throw Exception("unknown option '" + arg + "'");
 42                     }
 43                 }
 44                 else if (arg.StartsWith("-"))
 45                 {
 46                     string options = arg.Substring(1);
 47                     if (options.IsEmpty())
 48                     {
 49                         throw Exception("unknown argument '" + arg + "'");
 50                     }
 51                     else
 52                     {
 53                         bool unknown = false;
 54                         string uo;
 55                         for (char o : options)
 56                         {
 57                             switch (o)
 58                             {
 59                                 case 'h':
 60                                 {
 61                                     PrintHelp();
 62                                     return 1;
 63                                 }
 64                                 default:
 65                                 {
 66                                     unknown = true;
 67                                     uo.Append(o);
 68                                     break;
 69                                 }
 70                             }
 71                             if (unknown)
 72                             {
 73                                 throw Exception("unknown option '-" + uo + "'");
 74                             }
 75                         }
 76                     }
 77                 }
 78                 else
 79                 {
 80                     programSeen = true;
 81                     args.Add(arg);
 82                 }
 83             }
 84             else
 85             {
 86                 args.Add(arg);
 87             }
 88         }
 89         if (args.IsEmpty())
 90         {
 91             throw Exception("no program to execute");
 92         }
 93         int uid = GetUID();
 94         Users users = GetUsers();
 95         User* user = users.GetUser(uid);
 96         SetUID(0);
 97         SetGID(0);
 98         if (user->HasPassword())
 99         {
100             int pid = Fork();
101             if (pid == 0)
102             {
103                 List<string> loginArgs;
104                 loginArgs.Add("--user");
105                 loginArgs.Add(user->Name());
106                 Exec("/bin/login"loginArgs);
107             }
108             else
109             {
110                 byte loginExitCode = 0u;
111                 if (Wait(&loginExitCode) != -1)
112                 {
113                     if (loginExitCode != 0u)
114                     {
115                         return loginExitCode;
116                     }
117                 }
118                 else
119                 {
120                     throw Exception("login failed");
121                 }
122             }
123         }
124         int pid = Fork();
125         if (pid == 0)
126         {
127             string program = GetProgramFilePath(args[0]);
128             List<string> progArgs;
129             for (int i = 1; i < args.Count(); ++i;)
130             {
131                 progArgs.Add(args[i]);
132             }
133             Exec(programprogArgs);
134         }
135         else
136         {
137             byte exitCode = 0u;
138             if (Wait(&exitCode) != -1)
139             {
140                 return exitCode;
141             }
142             else
143             {
144                 throw Exception("error executing '" + args[0] + "'");
145             }
146         }
147     }
148     catch (const Exception& ex)
149     {
150         Console.Error() << ex.ToString() << endl();
151         return 1;
152     }
153     return 0;
154 }