first commit
This commit is contained in:
commit
b63786cc92
274
.clang-format
Normal file
274
.clang-format
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
AlignConsecutiveAssignments:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: true
|
||||||
|
AlignConsecutiveBitFields:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveDeclarations:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveMacros:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveShortCaseStatements:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCaseArrows: false
|
||||||
|
AlignCaseColons: false
|
||||||
|
AlignConsecutiveTableGenBreakingDAGArgColons:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveTableGenCondOperatorColons:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveTableGenDefinitionColons:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments:
|
||||||
|
Kind: Always
|
||||||
|
OverEmptyLines: 0
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowBreakBeforeNoexceptSpecifier: Never
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseExpressionOnASingleLine: true
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortCompoundRequirementOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: All
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: true
|
||||||
|
AfterClass: true
|
||||||
|
AfterControlStatement: Always
|
||||||
|
AfterEnum: true
|
||||||
|
AfterExternBlock: true
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterObjCDeclaration: true
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: true
|
||||||
|
BeforeCatch: true
|
||||||
|
BeforeElse: true
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: true
|
||||||
|
IndentBraces: true
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakAdjacentStringLiterals: true
|
||||||
|
BreakAfterAttributes: Leave
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakAfterReturnType: AllDefinitions
|
||||||
|
BreakArrays: true
|
||||||
|
BreakBeforeBinaryOperators: All
|
||||||
|
BreakBeforeConceptDeclarations: Always
|
||||||
|
BreakBeforeBraces: GNU
|
||||||
|
BreakBeforeInlineASMColon: OnlyMultiline
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakFunctionDefinitionParameters: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakStringLiterals: true
|
||||||
|
BreakTemplateDeclarations: MultiLine
|
||||||
|
ColumnLimit: 79
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: false
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IfMacros:
|
||||||
|
- KJ_IF_MAYBE
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentExternBlock: AfterExternBlock
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentRequiresClause: true
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertBraces: false
|
||||||
|
InsertNewlineAtEOF: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
IntegerLiteralSeparator:
|
||||||
|
Binary: 0
|
||||||
|
BinaryMinDigits: 0
|
||||||
|
Decimal: 0
|
||||||
|
DecimalMinDigits: 0
|
||||||
|
Hex: 0
|
||||||
|
HexMinDigits: 0
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLines:
|
||||||
|
AtEndOfFile: false
|
||||||
|
AtStartOfBlock: true
|
||||||
|
AtStartOfFile: true
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
LineEnding: DeriveLF
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MainIncludeChar: Quote
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PackConstructorInitializers: BinPack
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakOpenParenthesis: 0
|
||||||
|
PenaltyBreakScopeResolution: 500
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Right
|
||||||
|
PPIndentWidth: -1
|
||||||
|
QualifierAlignment: Leave
|
||||||
|
ReferenceAlignment: Pointer
|
||||||
|
ReflowComments: true
|
||||||
|
RemoveBracesLLVM: false
|
||||||
|
RemoveParentheses: Leave
|
||||||
|
RemoveSemicolon: false
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
RequiresExpressionIndentation: OuterScope
|
||||||
|
SeparateDefinitionBlocks: Leave
|
||||||
|
ShortNamespaceLines: 1
|
||||||
|
SkipMacroDefinitionBody: false
|
||||||
|
SortIncludes: CaseSensitive
|
||||||
|
SortJavaStaticImport: Before
|
||||||
|
SortUsingDeclarations: LexicographicNumeric
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeJsonColon: false
|
||||||
|
SpaceBeforeParens: Always
|
||||||
|
SpaceBeforeParensOptions:
|
||||||
|
AfterControlStatements: false
|
||||||
|
AfterForeachMacros: false
|
||||||
|
AfterFunctionDefinitionName: false
|
||||||
|
AfterFunctionDeclarationName: false
|
||||||
|
AfterIfMacros: false
|
||||||
|
AfterOverloadedOperator: false
|
||||||
|
AfterPlacementOperator: true
|
||||||
|
AfterRequiresInClause: false
|
||||||
|
AfterRequiresInExpression: false
|
||||||
|
BeforeNonEmptyParentheses: false
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: Never
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
|
SpacesInParens: Never
|
||||||
|
SpacesInParensOptions:
|
||||||
|
ExceptDoubleParentheses: false
|
||||||
|
InCStyleCasts: false
|
||||||
|
InConditionalStatements: false
|
||||||
|
InEmptyParentheses: false
|
||||||
|
Other: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: c++03
|
||||||
|
StatementAttributeLikeMacros:
|
||||||
|
- Q_EMIT
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TableGenBreakInsideDAGArg: DontBreak
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Never
|
||||||
|
VerilogBreakBetweenInstancePorts: true
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- STRINGIZE
|
||||||
|
...
|
||||||
|
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*.o
|
||||||
|
#*#
|
||||||
|
*~
|
||||||
|
bin/beroot
|
34
Makefile
Normal file
34
Makefile
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
CC=gcc
|
||||||
|
ECHO=echo -e
|
||||||
|
|
||||||
|
CFLAGS=-Wall -Werror -std=gnu99 -O0 -g
|
||||||
|
LIBS=-lcrypt
|
||||||
|
|
||||||
|
FILES=build/main.o
|
||||||
|
OUT=bin/beroot
|
||||||
|
|
||||||
|
all: $(FILES)
|
||||||
|
@$(ECHO) "Linking program"
|
||||||
|
@$(CC) $(CFLAGS) $(FILES) -o $(OUT) $(LIBS)
|
||||||
|
@$(ECHO) "Linking finished"
|
||||||
|
|
||||||
|
build/main.o: src/main.c src/config.h
|
||||||
|
@$(ECHO) "CC\t\t"$<
|
||||||
|
@$(CC) $(CFLAGS) $< -c -o $@ $(LIBS)
|
||||||
|
|
||||||
|
install: all
|
||||||
|
@$(ECHO) "Installing beroot (you MUST be root to install beroot)"
|
||||||
|
@cp $(OUT) /usr/bin
|
||||||
|
@chown root:root /usr/bin/beroot # set permissions
|
||||||
|
@chmod u+s /usr/bin/beroot
|
||||||
|
@$(ECHO) "Installation successful"
|
||||||
|
|
||||||
|
uninstall: all
|
||||||
|
@$(ECHO) "Uninstalling beroot (you MUST be root to uninstall beroot)"
|
||||||
|
@rm -f /usr/bin/beroot
|
||||||
|
@$(ECHO) "Uninstallation successful"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@$(ECHO) "Cleaning files..."
|
||||||
|
@rm -f $(FILES) $(OUT)
|
||||||
|
@$(ECHO) "Cleaning complete :)"
|
102
Readme.org
Normal file
102
Readme.org
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
* Beroot
|
||||||
|
|
||||||
|
Beroot is just another privilege escalation tool. I made Beroot for two reasons:
|
||||||
|
- I wanted to learn (I discovered a lot of new functions in the standard
|
||||||
|
library)
|
||||||
|
- Sudo is bloated, and wanted to do something smaller - but usable - than doas.
|
||||||
|
|
||||||
|
** Usage
|
||||||
|
|
||||||
|
Beroot is just two files: ~main.c~ the source of beroot, ~config,h~ the
|
||||||
|
configurations of the tool. Beroot doesn't have any ~.conf~ files that need to be
|
||||||
|
parsed or something similar, all the changes are made to the ~config.h~ file.
|
||||||
|
|
||||||
|
First, you'll need to build the program:
|
||||||
|
|
||||||
|
#+begin_src bash
|
||||||
|
make
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Now, you'll need to login as root to execute the following commands:
|
||||||
|
|
||||||
|
#+begin_src bash
|
||||||
|
make install
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
That command will copy ~./bin/beroot~ to ~/usr/bin~ and set the appropriate permissions to it.
|
||||||
|
|
||||||
|
** Configuration
|
||||||
|
|
||||||
|
The only thing you need to modify is the ~permissions~ variable in ~config.h~. This
|
||||||
|
file contains the following structure:
|
||||||
|
|
||||||
|
#+begin_src C
|
||||||
|
struct user_permissions
|
||||||
|
{
|
||||||
|
const char name[16384];
|
||||||
|
const char target_user[16384];
|
||||||
|
unsigned char permissions;
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
It only has three fields:
|
||||||
|
- ~name~: The name of the user you expect can use beroot (like the ones that
|
||||||
|
belong to the ~wheel~ group)
|
||||||
|
- ~target_user~: In case you want a user not to be root, but rather a different
|
||||||
|
user that exists on the machine, you can specify their name using this
|
||||||
|
variable.
|
||||||
|
- ~permissions~: Here you can set some of the following permission bits:
|
||||||
|
- ~PERM_ROOT~: If this is set, the user will execute commands as root,
|
||||||
|
~target_user~ will be ignored in this case.
|
||||||
|
- ~PERM_USER~: If this bit is present, the user will execute commands as
|
||||||
|
~target_user~ instead of root. If both ~PERM_ROOT~ and ~PERM_USER~ are present,
|
||||||
|
the last one is ignored as ~PERM_ROOT~ is checked first in the code.
|
||||||
|
- ~PERM_PASSWD~: If this is set, beroot will ask for the target user password
|
||||||
|
every time that the command is ran.
|
||||||
|
- ~PERM_NOPASSWD~: If this bit is present, beroot won't ask for the target user
|
||||||
|
password, it will just execute the specified command. Notice that either
|
||||||
|
~PERM_PASSWD~ or ~PERM_NOPASSWD~ must be present, if none of them are, beroot
|
||||||
|
will display an error.
|
||||||
|
|
||||||
|
For example, if we have a user called ~lain~ and we want this user to execute
|
||||||
|
commands as root, and not ask for a password, we'd add the following to the
|
||||||
|
~permissions~ variable in ~config.h~:
|
||||||
|
|
||||||
|
#+begin_src C
|
||||||
|
const static struct user_permissions permissions[] = {
|
||||||
|
{ .name = "lain",
|
||||||
|
.target_user = "\0",
|
||||||
|
.permissions = PERM_ROOT | PERM_NOPASSWD }
|
||||||
|
};
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
In that case, we are setting the user ~lain~ with the permissions of ~PERM_ROOT~
|
||||||
|
(execute commands as root) and ~PERM_NOPASSWD~ (don't ask for a password).
|
||||||
|
|
||||||
|
If we want to have multiple rules, we can just separate them by a comma (,):
|
||||||
|
|
||||||
|
#+begin_src C
|
||||||
|
const static struct user_permissions permissions[]
|
||||||
|
= { { .name = "lain",
|
||||||
|
.target_user = "\0",
|
||||||
|
.permissions = PERM_ROOT | PERM_NOPASSWD },
|
||||||
|
{ .name = "alyssa",
|
||||||
|
.target_user = "dbuser",
|
||||||
|
.permissions = PERM_USER | PERM_PASSWD } };
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
In that code now we have two users: ~lain~ with the settings we mentioned before,
|
||||||
|
and a new user ~alyssa~ that will execute commands as ~dbuser~ and ~PERM_PASSWD~ will
|
||||||
|
make that she has to enter her password every time she runs ~beroot~.
|
||||||
|
|
||||||
|
** TODO
|
||||||
|
|
||||||
|
I don't want to make this a big program, I want to keep everything as simple as
|
||||||
|
possible, but there are some things that I want to do:
|
||||||
|
- Optimise the code, I wrote this in like 1 hour just to test things in the
|
||||||
|
standard library.
|
||||||
|
- Some kind of persistency (there can be a ~PERM_PERSIST~ flag) so the password
|
||||||
|
doesn't need to be entered every time.
|
||||||
|
- Hide the password while it's being typed.
|
||||||
|
|
||||||
|
Those are the only things I have planned adding to beroot.
|
0
bin/.gitkeep
Normal file
0
bin/.gitkeep
Normal file
0
build/.gitkeep
Normal file
0
build/.gitkeep
Normal file
25
src/config.h
Normal file
25
src/config.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef __CONFIG_H
|
||||||
|
#define __CONFIG_H
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#define LOGIN_PASSWD_MAX 16384 // i think this is enough for a password?
|
||||||
|
|
||||||
|
#define PERM_ROOT 1 << 0 /* will be the root user */
|
||||||
|
#define PERM_USER 1 << 1 /* will be a custom specified user */
|
||||||
|
#define PERM_PASSWD 1 << 2 /* password is required */
|
||||||
|
#define PERM_NOPASSWD 1 << 3 /* password is not required */
|
||||||
|
|
||||||
|
struct user_permissions
|
||||||
|
{
|
||||||
|
const char name[LOGIN_NAME_MAX];
|
||||||
|
const char target_user[LOGIN_NAME_MAX];
|
||||||
|
unsigned char permissions;
|
||||||
|
};
|
||||||
|
|
||||||
|
const static struct user_permissions permissions[]
|
||||||
|
= { { .name = "lain",
|
||||||
|
.target_user = "\0",
|
||||||
|
.permissions = PERM_ROOT | PERM_NOPASSWD } };
|
||||||
|
|
||||||
|
#endif
|
181
src/main.c
Normal file
181
src/main.c
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <shadow.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
print_usage ()
|
||||||
|
{
|
||||||
|
puts ("usage: beroot command [args]");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_current_user_name ()
|
||||||
|
{
|
||||||
|
struct passwd *pwd = getpwuid (getuid ());
|
||||||
|
if (!pwd)
|
||||||
|
{
|
||||||
|
puts ("couldn't obtain your pwd");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pwd->pw_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct user_permissions *
|
||||||
|
user_in_permitted_users (char *name)
|
||||||
|
{
|
||||||
|
int total_users
|
||||||
|
= (int)(sizeof (permissions) / sizeof (struct user_permissions));
|
||||||
|
|
||||||
|
for (int i = 0; i < total_users; i++)
|
||||||
|
{
|
||||||
|
const struct user_permissions *current_user = &permissions[i];
|
||||||
|
if (!current_user)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strncmp (name, current_user->name, LOGIN_NAME_MAX) == 0)
|
||||||
|
return current_user;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct spwd *
|
||||||
|
obtain_target_swpd (const char *name)
|
||||||
|
{
|
||||||
|
if (!name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return getspnam (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
_Bool
|
||||||
|
authenticate_user (char *password, char *entered_password)
|
||||||
|
{
|
||||||
|
// the entered password ends with a \n, we remove it here
|
||||||
|
entered_password[strcspn (entered_password, "\n")] = '\0';
|
||||||
|
size_t password_len = strlen (password);
|
||||||
|
|
||||||
|
char *encrypted_password = crypt (entered_password, password);
|
||||||
|
int result = strncmp (password, encrypted_password, password_len);
|
||||||
|
if (result == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execute (char **command)
|
||||||
|
{
|
||||||
|
size_t total_commands = 0;
|
||||||
|
size_t maximum_commands = 10;
|
||||||
|
char **commands = calloc (sizeof (char *), maximum_commands);
|
||||||
|
if (!commands)
|
||||||
|
{
|
||||||
|
fputs ("Couldn't parse the commands\n", stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*command != NULL)
|
||||||
|
{
|
||||||
|
if (total_commands >= maximum_commands)
|
||||||
|
{
|
||||||
|
maximum_commands *= 2;
|
||||||
|
commands = realloc (commands, sizeof (char *) * maximum_commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
commands[total_commands] = *command;
|
||||||
|
|
||||||
|
command++;
|
||||||
|
total_commands++;
|
||||||
|
}
|
||||||
|
|
||||||
|
commands[total_commands] = NULL;
|
||||||
|
execvp (commands[0], commands);
|
||||||
|
|
||||||
|
free (commands);
|
||||||
|
commands = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
print_usage ();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *user_name = get_current_user_name ();
|
||||||
|
if (!user_name)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
const struct user_permissions *user = user_in_permitted_users (user_name);
|
||||||
|
if (!user)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s is not allowed to run commands, aborting\n",
|
||||||
|
user_name);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct spwd *target_swpd = user->permissions & PERM_ROOT
|
||||||
|
? obtain_target_swpd ("root")
|
||||||
|
: obtain_target_swpd (user->target_user);
|
||||||
|
if (!target_swpd)
|
||||||
|
{
|
||||||
|
fputs ("couldn't obtain the target user's shadow\n", stderr);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct passwd *target_passwd = getpwnam (target_swpd->sp_namp);
|
||||||
|
if (!target_passwd)
|
||||||
|
{
|
||||||
|
fputs ("couldn't obtain the passwd for the target user\n", stderr);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Give the user 3 attempts
|
||||||
|
_Bool is_authenticated = 0;
|
||||||
|
if (user->permissions & PERM_NOPASSWD)
|
||||||
|
{
|
||||||
|
is_authenticated = 1;
|
||||||
|
}
|
||||||
|
else if (user->permissions & PERM_PASSWD)
|
||||||
|
{
|
||||||
|
printf ("Enter the %s password: ", user->target_user);
|
||||||
|
char entered_password[LOGIN_PASSWD_MAX] = { 0 };
|
||||||
|
fgets (entered_password, LOGIN_PASSWD_MAX - 1, stdin);
|
||||||
|
is_authenticated
|
||||||
|
= authenticate_user (target_swpd->sp_pwdp, entered_password);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fputs (
|
||||||
|
"Please specify an authentication way, either PASSWD or NOPASSWD\n",
|
||||||
|
stderr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_authenticated)
|
||||||
|
{
|
||||||
|
fputs ("Couldn't authenticate you, please try again\n", stderr);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setuid (target_passwd->pw_uid) != 0)
|
||||||
|
{
|
||||||
|
fputs ("Couldn't switch to the target user\n", stderr);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
execute (argv + 1);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user