Browse code
merge branch 'cjpm-5222'
Showing 16 changed files
- .gitignore
- Makefile.in
- README.md
- dc_syslog.c
- dc_syslog.h
- dual_control.c
- dual_control_test.c
- logging.c
- logging.h
- logging_test
- logging_test.c
- test_support.h
- test_util.h
- token.c
- token.h
- token_test.c
... | ... |
@@ -1,7 +1,7 @@ |
1 | 1 |
MODULEFLAGS = -fPIC -fno-stack-protector |
2 |
-MODULEOBJS = dual_control.o logging.o dc_syslog.o |
|
3 |
-HEADERS = logging.h dc_syslog.h |
|
4 |
- |
|
2 |
+MODULEOBJS = dual_control.o logging.o token.o conversation.o |
|
3 |
+TESTOBJS = $(patsubst %.o, t_%.o, $(MODULEOBJS)) |
|
4 |
+HEADERS = logging.h test_support.h token.h |
|
5 | 5 |
MODULELIB = pam_dual_control.so |
6 | 6 |
UNAME_S := $(shell uname -s) |
7 | 7 |
|
... | ... |
@@ -15,6 +15,9 @@ dual_control.a: $(MODULEOBJS) |
15 | 15 |
$(MODULEOBJS): %.o: %.c $(HEADERS) |
16 | 16 |
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(MODULEFLAGS) $< -o $@ |
17 | 17 |
|
18 |
+$(TESTOBJS): t_%.o: %.c $(HEADERS) |
|
19 |
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $(MODULEFLAGS) -D UNIT_TEST $< -o $@ |
|
20 |
+ |
|
18 | 21 |
.PHONY: clean |
19 | 22 |
clean: |
20 | 23 |
@rm -f *.o *.a |
... | ... |
@@ -24,15 +27,21 @@ clean: |
24 | 27 |
distclean: clean |
25 | 28 |
@rm -f Makefile config.h |
26 | 29 |
|
27 |
-dual_control_test: dual_control_test.c dual_control.o |
|
30 |
+dual_control_test: dual_control_test.c t_dual_control.o |
|
28 | 31 |
$(CC) $(CFLAGS) $(CPPFLAGS) -lpam -o $@ $^ |
29 |
-logging_test: logging_test.c logging.o |
|
32 |
+ |
|
33 |
+logging_test: logging_test.c t_logging.o |
|
34 |
+ $(CC) $(CFLAGS) $(CPPFLAGS) -lpam -o $@ $^ |
|
35 |
+ |
|
36 |
+token_test: token_test.c t_token.o |
|
30 | 37 |
$(CC) $(CFLAGS) $(CPPFLAGS) -lpam -o $@ $^ |
31 | 38 |
|
32 | 39 |
.PHONY: test |
33 |
-test: dual_control_test logging_test |
|
34 |
- @./dual_control_test > /dev/null |
|
35 |
- @./logging_test > /dev/null |
|
40 |
+test: dual_control_test logging_test token_test |
|
41 |
+ @./dual_control_test |
|
42 |
+ @./logging_test |
|
43 |
+ @./token_test |
|
44 |
+ @echo all tests passed |
|
36 | 45 |
|
37 | 46 |
.PHONY: install |
38 | 47 |
install: $(MODULEOBJS) |
... | ... |
@@ -1,11 +1,13 @@ |
1 | 1 |
[![Build Status](https://travis-ci.org/cjdev/dual-control.svg?branch=master)](https://travis-ci.org/cjdev/dual-control) |
2 | 2 |
|
3 | 3 |
# Dual Control |
4 |
+Dual Control is a PAM module that requires a user to input a generated token from another user before being granted sudo access. The module also requires that the user input the reason for his or her access request and, via `syslog`, captures all this information for future reference. |
|
4 | 5 |
|
5 |
-Goal: To remove all non-firefighting developer write-access to production boxes |
|
6 |
+At **CJ Engineering**, we will be implementing Dual Control on our production boxes to ensure that a single engineer cannot gain write access without meeting the above-stated requirements. |
|
6 | 7 |
|
7 |
-For ZFR |
|
8 |
+Dual Control is an open source project licensed under the [GNU General Public License](https://github.com/cjdev/dual-control/blob/master/COPYING). As it stands, Dual Control is written only for machines running Linux. However, we graciously welcome contributions, particularly those related to portability to other operating systems. |
|
8 | 9 |
|
10 |
+## For ZFR |
|
9 | 11 |
* setup a native project |
10 | 12 |
* for Linux (docker, virtualbox) |
11 | 13 |
* installer |
12 | 14 |
deleted file mode 100644 |
... | ... |
@@ -1,17 +0,0 @@ |
1 |
-#include <stdarg.h> |
|
2 |
-#include "dc_syslog.h" |
|
3 |
- |
|
4 |
-void dc_openlog(const char *ident, int logopt, int facility) { |
|
5 |
- openlog(ident, logopt, facility); |
|
6 |
-} |
|
7 |
- |
|
8 |
-void dc_syslog(int priority, const char *format, ...) { |
|
9 |
- va_list varargs; |
|
10 |
- va_start(varargs, format); |
|
11 |
- vsyslog(priority, format, varargs); |
|
12 |
- va_end(varargs); |
|
13 |
-} |
|
14 |
-void dc_closelog(void) { |
|
15 |
- closelog(); |
|
16 |
-} |
|
17 |
- |
... | ... |
@@ -1,23 +1,39 @@ |
1 | 1 |
#include <security/pam_appl.h> |
2 | 2 |
#include <security/pam_modules.h> |
3 |
-#include <stdio.h> |
|
3 |
+#include <string.h> |
|
4 |
+#include <stdlib.h> |
|
5 |
+ |
|
4 | 6 |
#include "logging.h" |
5 | 7 |
#include "token.h" |
8 |
+#include "conversation.h" |
|
6 | 9 |
|
7 | 10 |
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { |
8 |
- printf("Authentication\n"); |
|
11 |
+ const char *returned_token = ask_for_token(pamh); |
|
12 |
+ |
|
13 |
+ int returned_token_length = strlen(returned_token); |
|
14 |
+ char working_token[returned_token_length + 1]; |
|
15 |
+ strcpy(working_token, returned_token); |
|
16 |
+ char *colon = strchr(working_token, ':'); |
|
17 |
+ if(!colon) { |
|
18 |
+ return PAM_AUTH_ERR; |
|
19 |
+ } |
|
20 |
+ |
|
21 |
+ *colon = 0; |
|
22 |
+ char *user = working_token; |
|
23 |
+ char *token = colon + 1; |
|
9 | 24 |
|
10 |
- int returned_validation = validate_token("str"); |
|
25 |
+ int returned_validation = validate_token(user, token); |
|
11 | 26 |
|
12 | 27 |
if (returned_validation) { |
13 | 28 |
log_success(); |
14 | 29 |
return PAM_SUCCESS; |
15 | 30 |
} else { |
31 |
+ log_failure(); |
|
16 | 32 |
return PAM_AUTH_ERR; |
17 | 33 |
} |
18 | 34 |
} |
19 | 35 |
|
20 | 36 |
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) { |
21 |
- printf("Set cred\n"); |
|
22 | 37 |
return PAM_SUCCESS; |
23 | 38 |
} |
39 |
+ |
... | ... |
@@ -4,25 +4,45 @@ |
4 | 4 |
|
5 | 5 |
#include "conversation.h" |
6 | 6 |
#include "token.h" |
7 |
+#include "test_util.h" |
|
7 | 8 |
|
9 |
+const char *validated_user = ""; |
|
10 |
+const char *validated_token = ""; |
|
8 | 11 |
const char *token_to_return = ""; |
12 |
+int validation_to_return = 0; |
|
13 |
+int log_success_invoked = 0; |
|
14 |
+int log_failure_invoked = 0; |
|
15 |
+int at_least_one_failed_test = 0; |
|
9 | 16 |
pam_handle_t *passed_pam_handle = NULL; |
17 |
+ |
|
18 |
+RESET_VARS_START |
|
19 |
+validated_user = ""; |
|
20 |
+validated_token = ""; |
|
21 |
+validation_to_return = 1; |
|
22 |
+passed_pam_handle = NULL; |
|
23 |
+log_success_invoked = 0; |
|
24 |
+log_failure_invoked = 0; |
|
25 |
+RESET_VARS_END |
|
26 |
+ |
|
10 | 27 |
const char *ask_for_token(pam_handle_t *pamh) { |
11 | 28 |
passed_pam_handle = pamh; |
12 | 29 |
return token_to_return; |
13 | 30 |
} |
14 | 31 |
|
15 |
-int validation_to_return = 0; |
|
16 |
-int validate_token(const char *token) { |
|
32 |
+ |
|
33 |
+int validate_token(const char *user, const char *token) { |
|
34 |
+ validated_user = user; |
|
35 |
+ validated_token = token; |
|
17 | 36 |
return validation_to_return; |
18 | 37 |
} |
19 | 38 |
|
20 |
- |
|
21 |
-int log_success_invoked = 0; |
|
22 | 39 |
void log_success() { |
23 | 40 |
log_success_invoked = 1; |
24 | 41 |
} |
25 | 42 |
|
43 |
+void log_failure() { |
|
44 |
+ log_failure_invoked = 1; |
|
45 |
+} |
|
26 | 46 |
|
27 | 47 |
int pam_sm_setcred_returns_success() { |
28 | 48 |
//given |
... | ... |
@@ -31,19 +51,45 @@ int pam_sm_setcred_returns_success() { |
31 | 51 |
int result = pam_sm_setcred(NULL, 0, 0, NULL); |
32 | 52 |
|
33 | 53 |
//then |
34 |
- return result == PAM_SUCCESS; |
|
54 |
+ checkint(PAM_SUCCESS, result, "function return"); |
|
55 |
+ succeed(); |
|
56 |
+ |
|
57 |
+} |
|
58 |
+ |
|
59 |
+int pam_sm_authenticate_validates_with_received_token() { |
|
60 |
+ // given |
|
61 |
+ token_to_return = "user:pin"; |
|
62 |
+ pam_handle_t *handle = (pam_handle_t*)""; |
|
63 |
+ |
|
64 |
+ // when |
|
65 |
+ pam_sm_authenticate(handle, 0, 0, NULL); |
|
66 |
+ |
|
67 |
+ // then |
|
68 |
+ checkstr("pin",validated_token, "validated token"); |
|
69 |
+ checkstr("user",validated_user, "validated user"); |
|
70 |
+ check(passed_pam_handle == handle, "incorrect handle"); |
|
71 |
+ succeed(); |
|
35 | 72 |
} |
36 | 73 |
|
37 | 74 |
int pam_sm_authenticate_success_invokes_log_success() { |
38 | 75 |
// given |
39 | 76 |
validation_to_return = 1; |
40 |
- log_success_invoked = 0; |
|
41 | 77 |
|
42 | 78 |
//when |
43 | 79 |
pam_sm_authenticate(NULL, 0, 0, NULL); |
44 | 80 |
return log_success_invoked; |
45 | 81 |
} |
46 | 82 |
|
83 |
+int pam_sm_authenticate_fail_invokes_log_failure() { |
|
84 |
+ // given |
|
85 |
+ validation_to_return = 0; |
|
86 |
+ |
|
87 |
+ //when |
|
88 |
+ pam_sm_authenticate(NULL, 0, 0, NULL); |
|
89 |
+ check(log_failure_invoked, "log failure should be invoked"); |
|
90 |
+ succeed(); |
|
91 |
+} |
|
92 |
+ |
|
47 | 93 |
int succeeds_with_valid_token() { |
48 | 94 |
//given |
49 | 95 |
validation_to_return = 1; |
... | ... |
@@ -66,35 +112,17 @@ int fails_with_invalid_token() { |
66 | 112 |
return result == PAM_AUTH_ERR; |
67 | 113 |
} |
68 | 114 |
|
69 |
-int main(int argc, char* argv[]) { |
|
70 |
- int test1_result = succeeds_with_valid_token(); |
|
71 |
- if (!test1_result) { |
|
72 |
- fprintf(stderr, "succeds with valid token failed\n"); |
|
73 |
- } |
|
74 |
- |
|
75 |
- int test3_result = pam_sm_setcred_returns_success(); |
|
76 |
- if (!test3_result) { |
|
77 |
- fprintf(stderr, "set cred failed\n"); |
|
78 |
- } |
|
79 |
- |
|
80 |
- int test4_result = pam_sm_authenticate_success_invokes_log_success(); |
|
81 |
- if (!test4_result) { |
|
82 |
- fprintf(stderr, "authenticate invokes log_success failed\n"); |
|
83 |
- } |
|
84 |
- |
|
85 |
- int test5_result = fails_with_invalid_token(); |
|
86 |
- if (!test5_result) { |
|
87 |
- fprintf(stderr, "fails with invalid token failed\n"); |
|
88 |
- } |
|
89 |
- |
|
90 |
- |
|
91 |
- |
|
92 |
- if (test1_result && test3_result && test4_result && test5_result) { |
|
93 |
- fprintf(stderr, "success\n"); |
|
94 |
- return 0; |
|
95 |
- } else { |
|
96 |
- return 1; |
|
97 |
- } |
|
115 |
+int runtests() { |
|
116 |
+ test(pam_sm_authenticate_validates_with_received_token); |
|
117 |
+ test(pam_sm_setcred_returns_success); |
|
118 |
+ test(pam_sm_authenticate_success_invokes_log_success); |
|
119 |
+ test(pam_sm_authenticate_fail_invokes_log_failure); |
|
120 |
+ test(succeeds_with_valid_token); |
|
121 |
+ test(fails_with_invalid_token); |
|
122 |
+ succeed(); |
|
98 | 123 |
} |
99 | 124 |
|
125 |
+int main(int argc, char* argv[]) { |
|
126 |
+ return !runtests(); |
|
127 |
+} |
|
100 | 128 |
|
... | ... |
@@ -1,12 +1,21 @@ |
1 |
+#include <syslog.h> |
|
2 |
+ |
|
1 | 3 |
#include "logging.h" |
2 |
-#include "dc_syslog.h" |
|
4 |
+#include "test_support.h" |
|
3 | 5 |
|
4 | 6 |
|
5 | 7 |
static const char program_name[] = "pam_dual_control"; |
6 | 8 |
|
7 | 9 |
void log_success() { |
8 |
- dc_openlog(program_name, 0, LOG_AUTHPRIV); |
|
9 |
- dc_syslog(LOG_NOTICE, "dual control succeeded"); |
|
10 |
- dc_closelog(); |
|
10 |
+ openlog(program_name, 0, LOG_AUTHPRIV); |
|
11 |
+ syslog(LOG_NOTICE, "dual control succeeded"); |
|
12 |
+ closelog(); |
|
13 |
+} |
|
14 |
+ |
|
15 |
+void log_failure() { |
|
16 |
+ openlog(program_name, 0, LOG_AUTHPRIV); |
|
17 |
+ syslog(LOG_NOTICE, "dual control failed"); |
|
18 |
+ closelog(); |
|
11 | 19 |
} |
12 | 20 |
|
21 |
+ |
... | ... |
@@ -1,53 +1,41 @@ |
1 | 1 |
#include <stdio.h> |
2 | 2 |
#include <string.h> |
3 |
+#include <syslog.h> |
|
3 | 4 |
|
4 |
-#include "dc_syslog.h" |
|
5 | 5 |
#include "logging.h" |
6 |
+#include "test_util.h" |
|
6 | 7 |
|
7 | 8 |
int logged_priority = -1000; |
8 | 9 |
const char *logged_message = ""; |
9 |
-void dc_syslog(int priority, const char *message, ...) { |
|
10 |
+void fake_syslog(int priority, const char *message, ...) { |
|
10 | 11 |
logged_priority = priority; |
11 | 12 |
logged_message = message; |
12 | 13 |
} |
13 | 14 |
|
14 | 15 |
int close_log_invoked = 0; |
15 |
-void dc_closelog(void) { |
|
16 |
+void fake_closelog(void) { |
|
16 | 17 |
close_log_invoked = 1; |
17 | 18 |
} |
18 | 19 |
|
19 | 20 |
int opened_facility = -1000; |
20 | 21 |
const char *opened_program_name = ""; |
21 | 22 |
int opened_logopt = -1000; |
22 |
-void dc_openlog(const char *ident, int logopt, int facility) { |
|
23 |
+void fake_openlog(const char *ident, int logopt, int facility) { |
|
23 | 24 |
opened_facility = facility; |
24 | 25 |
opened_program_name = ident; |
25 | 26 |
opened_logopt = logopt; |
26 | 27 |
} |
27 | 28 |
|
28 |
- |
|
29 |
-#define check(assertion, msg) \ |
|
30 |
- if (!(assertion)) { \ |
|
31 |
- fprintf(stderr, "assertion failed: %s\n", msg); \ |
|
32 |
- return 0; \ |
|
33 |
- } |
|
34 |
- |
|
35 |
-#define checkint(expected, actual, name) \ |
|
36 |
- check(expected == actual, name " should be " #expected) |
|
37 |
- |
|
38 |
-#define checkstr(expected, actual, name) \ |
|
39 |
- check(!strcmp(actual, expected), name " should be '" expected "'") |
|
40 |
- |
|
41 |
-#define succeed() return 1 |
|
29 |
+RESET_VARS_START |
|
30 |
+logged_priority = -1000; |
|
31 |
+close_log_invoked = 0; |
|
32 |
+opened_facility = -1000; |
|
33 |
+const char *opened_program_name = ""; |
|
34 |
+int opened_logopt = -1000; |
|
35 |
+RESET_VARS_END |
|
42 | 36 |
|
43 | 37 |
int test_log_success() { |
44 | 38 |
// given |
45 |
- opened_facility = -1000; |
|
46 |
- opened_program_name = ""; |
|
47 |
- opened_logopt = -1000; |
|
48 |
- logged_priority = -1000; |
|
49 |
- logged_message = ""; |
|
50 |
- close_log_invoked = 0; |
|
51 | 39 |
|
52 | 40 |
// when |
53 | 41 |
log_success(); |
... | ... |
@@ -59,17 +47,32 @@ int test_log_success() { |
59 | 47 |
check(close_log_invoked, "log closed"); |
60 | 48 |
checkstr("pam_dual_control", opened_program_name, "program name"); |
61 | 49 |
checkstr("dual control succeeded", logged_message, "logged message"); |
50 |
+ succeed(); |
|
51 |
+} |
|
52 |
+ |
|
53 |
+int test_log_failure() { |
|
54 |
+ //given |
|
62 | 55 |
|
56 |
+ //when |
|
57 |
+ log_failure(); |
|
58 |
+ |
|
59 |
+ //then |
|
60 |
+ checkint(LOG_AUTHPRIV, opened_facility, "facility"); |
|
61 |
+ checkint(LOG_NOTICE, logged_priority, "priority"); |
|
62 |
+ checkint(0, opened_logopt, "logopt"); |
|
63 |
+ check(close_log_invoked, "log closed"); |
|
64 |
+ checkstr("pam_dual_control", opened_program_name, "program name"); |
|
65 |
+ checkstr("dual control failed", logged_message, "logged message"); |
|
63 | 66 |
succeed(); |
64 | 67 |
} |
65 | 68 |
|
69 |
+int test_runner() { |
|
70 |
+ test(test_log_success); |
|
71 |
+ test(test_log_failure); |
|
72 |
+ succeed(); |
|
73 |
+} |
|
66 | 74 |
|
67 | 75 |
int main(int numargs, char **args) { |
68 |
- if(test_log_success()) { |
|
69 |
- fprintf(stderr, "Success!\n"); |
|
70 |
- return 0; |
|
71 |
- } else { |
|
72 |
- return 1; |
|
73 |
- } |
|
76 |
+ return !test_runner(); |
|
74 | 77 |
} |
75 | 78 |
|
76 | 79 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,48 @@ |
1 |
+/* Include this in a module that will be under test coverage |
|
2 |
+ * |
|
3 |
+ */ |
|
4 |
+ |
|
5 |
+#ifndef _TEST_SUPPORT_H |
|
6 |
+#define _TEST_SUPPORT_H |
|
7 |
+#include <stdlib.h> |
|
8 |
+#include <stdio.h> |
|
9 |
+#include <pwd.h> |
|
10 |
+#include <sys/stat.h> |
|
11 |
+// SYSLOG |
|
12 |
+void fake_openlog(const char *ident, int logopt, int facility); |
|
13 |
+void fake_syslog(int priority, const char *format, ...); |
|
14 |
+void fake_closelog(void); |
|
15 |
+ |
|
16 |
+// PWD |
|
17 |
+int fake_getpwnam_r(const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result); |
|
18 |
+ |
|
19 |
+// SYS_STAT |
|
20 |
+int fake_stat(const char *path, struct stat *stat); |
|
21 |
+ |
|
22 |
+// STDIO |
|
23 |
+FILE *fake_fopen(const char *path, const char *mode); |
|
24 |
+char *fake_fgets(char *buf, int n, FILE *fp); |
|
25 |
+int fake_fclose(FILE *fp); |
|
26 |
+ |
|
27 |
+ |
|
28 |
+#ifdef UNIT_TEST |
|
29 |
+// SYSLOG |
|
30 |
+#define openlog(IDENT, LOGOPT, FACILITY) fake_openlog(IDENT, LOGOPT, FACILITY) |
|
31 |
+#define syslog(PRIORITY, ...) fake_syslog(PRIORITY, __VA_ARGS__) |
|
32 |
+#define closelog() fake_closelog() |
|
33 |
+ |
|
34 |
+// PWD |
|
35 |
+#define getpwnam_r(USER, PASSWD, BUFFER, BUFSIZE, PRESULT) fake_getpwnam_r(USER, PASSWD, BUFFER, BUFSIZE, PRESULT) |
|
36 |
+ |
|
37 |
+// SYS_STAT |
|
38 |
+#define stat(PATH, STRUCT) fake_stat(PATH, STRUCT) |
|
39 |
+ |
|
40 |
+// STDIO |
|
41 |
+#define fopen(PATH, MODE) fake_fopen(PATH, MODE) |
|
42 |
+#define fgets(DEST, DEST_SIZE, FILE_HANDLE) fake_fgets(DEST, DEST_SIZE, FILE_HANDLE) |
|
43 |
+#define fclose(FILE_HANDLE) fake_fclose(FILE_HANDLE) |
|
44 |
+ |
|
45 |
+#endif |
|
46 |
+ |
|
47 |
+#endif |
|
48 |
+ |
0 | 49 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,36 @@ |
1 |
+#ifndef _TESTUTIL_H |
|
2 |
+#define _TESTUTIL_H |
|
3 |
+ |
|
4 |
+#include <string.h> |
|
5 |
+#include <stdio.h> |
|
6 |
+#define check(assertion, msg) \ |
|
7 |
+ if (!(assertion)) { \ |
|
8 |
+ fprintf(stderr, "assertion failed: %s\n", msg); \ |
|
9 |
+ return 0; \ |
|
10 |
+ } |
|
11 |
+ |
|
12 |
+#define checkint(expected, actual, name) \ |
|
13 |
+ check(expected == actual, name " should be " #expected) |
|
14 |
+ |
|
15 |
+#define checkstr(expected, actual, name) \ |
|
16 |
+ check(!strcmp(expected, actual), name " should be '" expected "'") |
|
17 |
+ |
|
18 |
+#define RESET_VARS_START void __reset_vars() { |
|
19 |
+ |
|
20 |
+#define RESET_VARS_END } |
|
21 |
+ |
|
22 |
+#define test(NAME) \ |
|
23 |
+ { \ |
|
24 |
+ __reset_vars(); \ |
|
25 |
+ int result = NAME (); \ |
|
26 |
+ if (!result) { \ |
|
27 |
+ fprintf(stderr, "test failed: %s\n", #NAME); \ |
|
28 |
+ return 0; \ |
|
29 |
+ } \ |
|
30 |
+ } |
|
31 |
+ |
|
32 |
+#define succeed() return 1 |
|
33 |
+#define fail() return 0 |
|
34 |
+ |
|
35 |
+#endif |
|
36 |
+ |
0 | 37 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,103 @@ |
1 |
+#include <stdlib.h> |
|
2 |
+#include <string.h> |
|
3 |
+#include <security/pam_modules.h> |
|
4 |
+#include <pwd.h> |
|
5 |
+#include <unistd.h> |
|
6 |
+#include <stdio.h> |
|
7 |
+#include <sys/stat.h> |
|
8 |
+ |
|
9 |
+#include "token.h" |
|
10 |
+#include "test_support.h" |
|
11 |
+ |
|
12 |
+typedef struct buffer { |
|
13 |
+ size_t size; |
|
14 |
+ char *mem; |
|
15 |
+} buffer_t; |
|
16 |
+ |
|
17 |
+buffer_t allocate_buffer() { |
|
18 |
+ buffer_t buffer; |
|
19 |
+ |
|
20 |
+ buffer.size = (size_t) sysconf(_SC_GETPW_R_SIZE_MAX); |
|
21 |
+ buffer.mem = (char *) malloc(buffer.size * sizeof(char)); |
|
22 |
+ |
|
23 |
+ return buffer; |
|
24 |
+ |
|
25 |
+} |
|
26 |
+ |
|
27 |
+void free_buffer(buffer_t *buffer) { |
|
28 |
+ free(buffer->mem); |
|
29 |
+ buffer->mem = 0; |
|
30 |
+ buffer->size = 0; |
|
31 |
+} |
|
32 |
+ |
|
33 |
+char *use_buffer(buffer_t buffer) { |
|
34 |
+ return buffer.mem; |
|
35 |
+} |
|
36 |
+ |
|
37 |
+size_t buffer_size(buffer_t buffer) { |
|
38 |
+ return buffer.size; |
|
39 |
+} |
|
40 |
+ |
|
41 |
+ |
|
42 |
+int get_passwd(const char *user, struct passwd *passwd, buffer_t buffer) { |
|
43 |
+ struct passwd *found_passwd = 0; |
|
44 |
+ getpwnam_r(user, passwd, use_buffer(buffer), buffer_size(buffer), &found_passwd); |
|
45 |
+ return (found_passwd != 0); |
|
46 |
+} |
|
47 |
+ |
|
48 |
+int validate_token(const char *user, const char *token) { |
|
49 |
+ |
|
50 |
+ |
|
51 |
+ char *filepath = 0; |
|
52 |
+ char *working_token = 0; |
|
53 |
+ buffer_t buffer = allocate_buffer(); |
|
54 |
+ |
|
55 |
+ int ok = 0; |
|
56 |
+ struct passwd passwd; |
|
57 |
+ int user_found = get_passwd(user, &passwd, buffer); |
|
58 |
+ |
|
59 |
+ // check if user is known |
|
60 |
+ if(!user_found) { |
|
61 |
+ goto finally; |
|
62 |
+ } |
|
63 |
+ |
|
64 |
+ const char *directory = passwd.pw_dir; |
|
65 |
+ |
|
66 |
+ int dir_len = strlen(directory); |
|
67 |
+ int fname_len = strlen(".dual_control"); |
|
68 |
+ filepath = (char *)malloc((dir_len + 1 + fname_len + 1) * sizeof(char)); |
|
69 |
+ |
|
70 |
+ strcpy(filepath, directory); |
|
71 |
+ strcat(filepath, "/"); |
|
72 |
+ strcat(filepath, ".dual_control"); |
|
73 |
+ |
|
74 |
+ struct stat file_stat; |
|
75 |
+ int check_file = stat(filepath, &file_stat); |
|
76 |
+ if (check_file) { |
|
77 |
+ goto finally; |
|
78 |
+ } |
|
79 |
+ |
|
80 |
+ // read the file and grab token |
|
81 |
+ char fetched_token[7]; |
|
82 |
+ FILE *fp = 0; |
|
83 |
+ fp = fopen(filepath, "r"); |
|
84 |
+ fgets(fetched_token, 7, fp); |
|
85 |
+ fclose(fp); |
|
86 |
+ |
|
87 |
+ // check if token matches |
|
88 |
+ if(strcmp(token, fetched_token)) { |
|
89 |
+ goto finally; |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ ok = 1; |
|
93 |
+ |
|
94 |
+ finally: |
|
95 |
+ |
|
96 |
+ free(filepath); |
|
97 |
+ free(working_token); |
|
98 |
+ free_buffer(&buffer); |
|
99 |
+ |
|
100 |
+ return ok; |
|
101 |
+} |
|
102 |
+ |
|
103 |
+ |
7 | 7 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,120 @@ |
1 |
+#include <string.h> |
|
2 |
+#include <pwd.h> |
|
3 |
+#include <stdio.h> |
|
4 |
+#include <sys/stat.h> |
|
5 |
+ |
|
6 |
+#include "token.h" |
|
7 |
+#include "test_util.h" |
|
8 |
+ |
|
9 |
+const char *fake_user = ""; |
|
10 |
+const char *fake_user_token = ""; |
|
11 |
+ |
|
12 |
+// all the fake system calls |
|
13 |
+char *fake_home_dir = ""; |
|
14 |
+int fake_getpwnam_r(const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) { |
|
15 |
+ strcpy(buffer, fake_home_dir); |
|
16 |
+ pwd->pw_dir = buffer; |
|
17 |
+ int ok = !strcmp(nam, fake_user); |
|
18 |
+ *result = ok ? pwd : 0; |
|
19 |
+ return !ok; |
|
20 |
+} |
|
21 |
+ |
|
22 |
+ |
|
23 |
+char *fake_stat_path = ""; |
|
24 |
+int fake_stat(const char *path, struct stat *stat) { |
|
25 |
+ return (strcmp(fake_stat_path, path)); |
|
26 |
+} |
|
27 |
+ |
|
28 |
+char *fake_fopen_path = ""; |
|
29 |
+char *fake_fopen_mode = ""; |
|
30 |
+FILE *_fhandle = 0; |
|
31 |
+FILE *fake_fopen(const char *path, const char *mode) { |
|
32 |
+ static FILE handle; |
|
33 |
+ int path_matches = !strcmp(fake_fopen_path, path); |
|
34 |
+ int mode_matches = !strcmp(fake_fopen_mode, mode); |
|
35 |
+ if(path_matches && mode_matches) { |
|
36 |
+ _fhandle = &handle; |
|
37 |
+ return &handle; |
|
38 |
+ } else { |
|
39 |
+ _fhandle = 0; |
|
40 |
+ return 0; |
|
41 |
+ } |
|
42 |
+} |
|
43 |
+ |
|
44 |
+char *fake_fgets(char *buf, int n, FILE *fp) { |
|
45 |
+ if (_fhandle == fp && fp != 0) { |
|
46 |
+ strncpy(buf, fake_user_token, n - 1); |
|
47 |
+ return buf; |
|
48 |
+ } else { |
|
49 |
+ return 0; |
|
50 |
+ } |
|
51 |
+} |
|
52 |
+ |
|
53 |
+int fake_fclose(FILE *fp) { |
|
54 |
+ return 0; |
|
55 |
+} |
|
56 |
+ |
|
57 |
+ |
|
58 |
+// STDIO |
|
59 |
+ |
|
60 |
+ |
|
61 |
+ |
|
62 |
+RESET_VARS_START |
|
63 |
+fake_user = "msmith"; |
|
64 |
+fake_user_token = "123456"; |
|
65 |
+fake_home_dir = "/home/msmith"; |
|
66 |
+fake_stat_path = "/home/msmith/.dual_control"; |
|
67 |
+fake_fopen_path = fake_stat_path; |
|
68 |
+fake_fopen_mode = "r"; |
|
69 |
+RESET_VARS_END |
|
70 |
+ |
|
71 |
+ |
|
72 |
+int validate_compares_to_user_token() { |
|
73 |
+ |
|
74 |
+ // given |
|
75 |
+ |
|
76 |
+ // when |
|
77 |
+ int valid = validate_token("msmith", "123456"); |
|
78 |
+ |
|
79 |
+ // then |
|
80 |
+ check(valid, "expected result to be valid"); |
|
81 |
+ |
|
82 |
+ succeed(); |
|
83 |
+ |
|
84 |
+} |
|
85 |
+ |
|
86 |
+int validates_from_the_right_user() { |
|
87 |
+ //given |
|
88 |
+ |
|
89 |
+ //when |
|
90 |
+ int valid = validate_token("jbalcita", "12346"); |
|
91 |
+ |
|
92 |
+ //then |
|
93 |
+ check(!valid, "expected result to be invalid"); |
|
94 |
+ succeed(); |
|
95 |
+} |
|
96 |
+ |
|
97 |
+int validates_user_specific_token() { |
|
98 |
+ //given |
|
99 |
+ |
|
100 |
+ //when |
|
101 |
+ int valid = validate_token("msmith", "654321"); |
|
102 |
+ |
|
103 |
+ //then |
|
104 |
+ check(!valid, "expected result to be invalid"); |
|
105 |
+ succeed(); |
|
106 |
+} |
|
107 |
+ |
|
108 |
+int runtests() { |
|
109 |
+ test(validate_compares_to_user_token); |
|
110 |
+ test(validates_from_the_right_user); |
|
111 |
+ test(validates_user_specific_token); |
|
112 |
+ succeed(); |
|
113 |
+} |
|
114 |
+ |
|
115 |
+int main(int argc, char **argv) { |
|
116 |
+ int rval = !runtests(); |
|
117 |
+ return rval; |
|
118 |
+} |
|
119 |
+ |
|
120 |
+ |