List of commits:
Subject Hash Author Date (UTC)
Checkpoint 049e12584744b8a51bfc5867fd0e7b2db0592deb Catalin(ux) M. BOIE 2018-02-11 22:25:13
Fixed a bug in totp, added keys in memory abec61861e2f37398026dbe7342d7751390e95d8 Catalin(ux) M. BOIE 2018-02-04 18:36:12
Initial version c641fafbd46342cd24fde45129cc3637b7ca65bc Catalin(ux) M. BOIE 2018-02-03 23:42:32
Commit 049e12584744b8a51bfc5867fd0e7b2db0592deb - Checkpoint
Author: Catalin(ux) M. BOIE
Author date (UTC): 2018-02-11 22:25
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2018-02-11 22:25
Parent(s): abec61861e2f37398026dbe7342d7751390e95d8
Signing key:
Tree: 5bd0aef3ab4ac41696c9d45a3d447d4e3444fc17
File Lines added Lines deleted
.gitignore 3 1
Makefile 0 34
Makefile.in 48 0
README 5 13
TODO 20 13
brute.c 113 0
brute.h 4 0
conf.c 122 0
conf.h 10 0
configure 3 0
duilder 689 0
duilder.conf 33 0
key.c 37 15
key.h 3 2
nf-queue.c 0 172
nf2fa.conf.sample 25 0
nf2fa.spec.in 42 0
nf2fa_common.h.in 2 2
nf2fac.c 127 36
nf2fad.c 278 129
nf2fad.val 5 0
protocol.c 0 3
totp.c 24 13
totp.h 2 1
util.c 37 5
util.h 2 0
File .gitignore changed (mode: 100644) (index ef4bba7..f6b11f3)
1 1 nf2fac nf2fac
2 2 nf2fad nf2fad
3 3 *.o *.o
4
4 nf2fa_common.h
5 Makefile
6 nf2fa.spec
File Makefile deleted (index 6052c9b..0000000)
1 TARGETS := nf2fad nf2fac #nf2fa_check
2
3 all: $(TARGETS)
4
5 CFLAGS := -Wall -Wextra -g -O2 $(CFLAGS)
6
7 OBJS := totp.o key.o protocol.o util.o
8 LIBS := -lmnl -lnetfilter_queue -lssl -lcrypto -lqrencode
9
10 totp.o: totp.c totp.h
11 gcc $(CFLAGS) totp.c -c
12
13 key.o: key.c key.h
14 gcc $(CFLAGS) key.c -c
15
16 protocol.o: protocol.c protocol.h
17 gcc $(CFLAGS) protocol.c -c
18
19 nf2fad: nf2fad.c $(OBJS) totp.h key.h protocol.h util.h
20 gcc $(CFLAGS) nf2fad.c -o nf2fad $(OBJS) $(LIBS)
21
22 nf2fac: nf2fac.c $(OBJS) totp.h key.h protocol.h util.h
23 gcc $(CFLAGS) nf2fac.c -o nf2fac $(OBJS) $(LIBS)
24
25 nf2fa_check: nf2fa_check.c $(OBJS) totp.h
26 gcc $(CFLAGS) nf2fa_check.c -o nf2fa_check $(OBJS) $(LIBS)
27
28 .PHONY: clean
29 clean:
30 @rm -fv $(TARGETS) $(OBJS)
31
32 .PHONY: check
33 check:
34 cppcheck --enable=all -I. .
File Makefile.in added (mode: 100644) (index 0000000..fdade10)
1 TARGETS := nf2fad nf2fac
2
3 all: $(TARGETS)
4
5 CFLAGS := -Wall -Wextra -g -O2 @CC_SWITCHES@ $(CFLAGS)
6
7 OBJS := totp.o key.o protocol.o util.o conf.o brute.o
8 LIBS := -lmnl -lnetfilter_queue -lssl -lcrypto -lqrencode -lcap
9 DEP := Makefile
10
11 util.o: util.c util.h $(DEP)
12 gcc $(CFLAGS) util.c -c
13
14 totp.o: totp.c totp.h $(DEP)
15 gcc $(CFLAGS) totp.c -c
16
17 key.o: key.c key.h $(DEP)
18 gcc $(CFLAGS) key.c -c
19
20 protocol.o: protocol.c protocol.h $(DEP)
21 gcc $(CFLAGS) protocol.c -c
22
23 conf.o: conf.c conf.h $(DEP)
24 gcc $(CFLAGS) conf.c -c
25
26 brute.o: brute.c brute.h $(DEP)
27 gcc $(CFLAGS) brute.c -c
28
29 nf2fad: nf2fad.c $(OBJS) totp.h key.h protocol.h util.h conf.h brute.h $(DEP)
30 gcc $(CFLAGS) nf2fad.c -o nf2fad $(OBJS) $(LIBS)
31
32 nf2fac: nf2fac.c $(OBJS) totp.h key.h protocol.h util.h $(DEP)
33 gcc $(CFLAGS) nf2fac.c -o nf2fac $(OBJS) $(LIBS)
34
35 .PHONY: clean
36 clean:
37 @rm -fv $(TARGETS) $(OBJS)
38 @-rm -f $(PRJ)-*.rpm $(PRJ)-*-*-*.tgz $(PRJ)-*.tar.gz
39
40 .PHONY: check
41 check:
42 cppcheck --enable=all -I. .
43
44 install: all
45 @mkdir -p $(I_USR_SBIN)
46 @cp -vd nf2fad $(I_USR_SBIN)
47 @mkdir -p $(I_USR_BIN)
48 @cp -vd nf2fac $(I_USR_BIN)
File README changed (mode: 100644) (index 75b8358..3aad56c)
1 Build dependency: libnetfilter_queue-devel libmnl-devel qrencode-devel
2
3 We also will store them in RAM, to be able to check them.
4
5 At boot, load all files and store them in ram; limit per user.
6
7 Of course, also root must be able to enroll.
1 Name: nf2fa
2 Description: Port knocking meets two-factor authentication (2fa)
3 Start date: 1st Feb 2018
4 Author: Catalin(ux) M. BOIE
8 5
9 6 Why we need this? Why we need this?
10 7 - Because classic port knocking can be replicated from anywhere, if the attacker - Because classic port knocking can be replicated from anywhere, if the attacker
11 8 can "see" the packets. can "see" the packets.
12 - With a digital signature program, you need some part on the client side.
9 - With a digital signature program, you need some code on the client side.
13 10 - -
14
15 Directory layout for storing 2fa keys:
16 KEY_DIR (/var/lib/nf2fa)
17 uid
18 XXX
File TODO changed (mode: 100644) (index 7b1ba9f..96fb1fd)
1 [ ] To prevent traffic hijack, we may want to block both users when
2 we receive 2 packets from different IPs in a short interval (3 seconds)?
3 But, we can have a DOS here! So, maybe not do it.
4 Warn user that nf2fa is not for allowing non authenticated connections.
5 [ ] Create /var/lib/nf2fa; pay attention to rights
6 Refuse to load keys if the rights are not ok.
7 [ ] Clean keys from memory!
8 [ ] Show the date of the enrollment
9 [ ] Order the listing?
10 [ ] How to store keys in memory? Should I?
11 [ ] Drop privileges.
12 [ ] Allow user to send a code to close the firewall.
13 [ ] When searching for the next free slot, search in memory, not on disk!
1 [ ] Warn user that nf2fa is not for allowing non authenticated connections.
2 [ ] Document commands.
3 [ ] Test brute force.
4 [ ] Document what rules have to be added in firewall (also for shorewall).
5 [ ]
6
7 == Future ==
8 [ ] Dynamic allocate my_ips, size in conf.
9 [ ] move load_keys to keys.c?
10 [ ] Clean keys from memory! No possible, but use an XOR?
11 [ ] Allow (in conf) to select what string is needed for unlock (pin, uid,
12 key_id etc.)
13 [ ] Should we also generate scratch codes?
14 [ ] Add possibility for admin to change the configuration using nf2fac, but
15 testing for uid 0.
16 [ ] Save the bad_entries/my_ips tables on disk?
17 [ ] conf: log file = syslog => syslog
18 [ ] Command to open the firewall till close command received?
19 [ ] When we give 'close' command, remove all IPs associated with that uid?
20 Separate command!
14 21 [ ] [ ]
File brute.c added (mode: 100644) (index 0000000..7125840)
1 /*
2 * Brute force attack using a hash table based on source IP.
3 * We will not check the packets which are too close in time.
4 * https://en.wikipedia.org/wiki/Jenkins_hash_function
5 */
6
7 #define _GNU_SOURCE
8
9 #include <sys/time.h>
10 #include <sys/random.h>
11 #include <stdio.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <stdlib.h>
15
16 #include "brute.h"
17
18 static unsigned char secret[8];
19 static unsigned int bad_entries;
20 static time_t *brute_table;
21
22 static char error[256];
23
24 char *brute_error(void)
25 {
26 return error;
27 }
28
29 /*
30 * Hash function
31 */
32 static unsigned int brute_hash(const unsigned char *src,
33 const unsigned char src_len)
34 {
35 unsigned char i = 0;
36 unsigned int hash = 0;
37
38 while (i != src_len) {
39 hash += src[i++];
40 hash += hash << 10;
41 hash ^= hash >> 6;
42 }
43
44 // mix secret
45 i = 0;
46 while (i < sizeof(secret)) {
47 hash += secret[i++];
48 hash += hash << 10;
49 hash ^= hash >> 6;
50 }
51
52 hash += hash << 3;
53 hash ^= hash >> 11;
54 hash += hash << 15;
55
56 return hash;
57 }
58
59 /*
60 * Init brute force system
61 */
62 int brute_init(const unsigned int entries)
63 {
64 int r;
65
66 if (entries == 0) {
67 snprintf(error, sizeof(error),
68 "bad entries size cannot be zero");
69 return -1;
70 }
71
72 bad_entries = entries;
73
74 brute_table = malloc(bad_entries * sizeof(time_t));
75 if (!brute_table) {
76 snprintf(error, sizeof(error),
77 "cannot alloc memory for bad entries");
78 return -1;
79 }
80
81 memset(brute_table, 0, bad_entries * sizeof(time_t));
82
83 r = getrandom(secret, sizeof(secret), 0);
84 if (r != sizeof(secret)) {
85 snprintf(error, sizeof(error),
86 "cannot get random bytes to populate the secret: %s",
87 strerror(errno));
88 free(brute_table);
89 return -1;
90 }
91
92 return 0;
93 }
94
95 /*
96 * Look up an IP, and if not present, store it
97 * Returns 0 if IP was not present or it is ok to check it again.
98 * Returns -1 if we just need to drop the packet.
99 */
100 int brute_check(const unsigned char *src, const unsigned char src_len,
101 const time_t now)
102 {
103 unsigned int h;
104
105 h = brute_hash(src, src_len) % bad_entries;
106
107 if (brute_table[h] + 10 < now) {
108 brute_table[h] = now;
109 return 0;
110 }
111
112 return -1;
113 }
File brute.h added (mode: 100644) (index 0000000..6a8b864)
1 char *brute_error(void);
2 int brute_init(const unsigned int bad_entries);
3 int brute_check(const unsigned char *src, const unsigned char src_len,
4 const time_t now);
File conf.c added (mode: 100644) (index 0000000..c85ca00)
1 #define _GNU_SOURCE
2
3 #include <unistd.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10
11 #include "util.h"
12 #include "conf.h"
13
14 unsigned short queue = 4444;
15 unsigned int bad_entries = 4096;
16 char *sock_path = "/etc/nf2fa.sock";
17 unsigned int grant_time = 3600;
18
19 /*
20 * Log configuration options
21 */
22 static void log_conf(void)
23 {
24 xlog("queue: %u\n", queue);
25 xlog("bad entries: %u\n", bad_entries);
26 xlog("sock: %s\n", sock_path);
27 xlog("grant time: %u\n", grant_time);
28 }
29
30 /*
31 * Loading configuration
32 * Return -1 on error, 0 on success
33 */
34 int conf_load(const char *file)
35 {
36 int err = -1, r;
37 FILE *f;
38 struct stat s;
39
40 r = stat(file, &s);
41 if (r == -1) {
42 log_conf();
43 return 0;
44 }
45
46 f = fopen(file, "r");
47 if (!f) {
48 xerr("Cannot open conf file (%s): %s!\n",
49 file, strerror(errno));
50 return err;
51 }
52
53 while (1) {
54 char buf[128], *q, *s, *val;
55 unsigned short len;
56
57 q = fgets(buf, sizeof(buf), f);
58 if (!q) {
59 err = 0;
60 log_conf();
61 break;
62 }
63
64 if ((*buf == '#') || (*buf == '\r') || (*buf == '\n'))
65 continue;
66
67 s = strchr(buf, '\r');
68 if (s)
69 *s = '\0';
70 s = strchr(buf, '\n');
71 if (s)
72 *s = '\0';
73
74 s = strchr(buf, '=');
75 if (!s) {
76 xerr("Invalid conf line [%s]!\n", buf);
77 break;
78 }
79 *s = '\0';
80 len = strlen(buf);
81 while (strchr("\r\n\t", buf[len - 1])) {
82 buf[len - 1] = '\0';
83 len--;
84 }
85
86 val = s + 1;
87 while (*val == ' ')
88 val++;
89 len = strlen(val);
90 while (strchr("\r\n\t", val[len - 1])) {
91 val[len - 1] = '\0';
92 len--;
93 }
94
95 //xlog("DEBUG: var=[%s] value=[%s]\n", buf, val);
96
97 if (strcmp(buf, "queue") == 0) {
98 queue = strtoul(val, NULL, 0);
99 continue;
100 }
101
102 if (strcmp(buf, "bad entries") == 0) {
103 bad_entries = strtoul(val, NULL, 0);
104 continue;
105 }
106
107 if (strcmp(buf, "sock") == 0) {
108 sock_path = strdup(val);
109 continue;
110 }
111
112 if (strcmp(buf, "grant time") == 0) {
113 grant_time = strtoul(val, NULL, 0);
114 continue;
115 }
116
117 xerr("Invalid conf option: %s\n", buf);
118 }
119 fclose(f);
120
121 return err;
122 }
File conf.h added (mode: 100644) (index 0000000..43e871c)
1 #define CONF_FILE "/etc/nf2fa.conf"
2
3 extern unsigned short queue;
4 extern unsigned int bad_entries;
5 extern char *sock_path;
6 extern unsigned int grant_time;
7
8
9 int conf_load(const char *file);
10
File configure added (mode: 100755) (index 0000000..92c4bc4)
1 #!/bin/bash
2
3 ./duilder "${@}"
File duilder added (mode: 100755) (index 0000000..274273c)
1 #!/bin/bash
2
3 set -e
4
5 function duilder_final()
6 {
7 PRJ="${1}"
8 VER="${2}"
9 RELEASE_SCRIPT="${3}"
10
11 # Run release script
12 if [ ! -z "${RELEASE_SCRIPT}" -a -x "${RELEASE_SCRIPT}" ]; then
13 echo "[*] Running ${RELEASE_SCRIPT}..."
14 ${RELEASE_SCRIPT}
15 fi
16 }
17
18 function duilder_docs()
19 {
20 PRJ="${1}"
21 VER="${2}"
22 EXPORT_PATH="${3}"
23
24 if [ ! -d "${EXPORT_PATH}" ]; then
25 echo "[*] WARN: ${EXPORT_PATH} does not exists. Creating it..."
26 mkdir -p "${EXPORT_PATH}"
27 fi
28
29 if [ "${BUILD_SDEB}" = "1" ]; then
30 if [ -d "debian" ]; then
31 >debian/docs
32 fi
33 fi
34
35 echo "[*] Copying docs to [${EXPORT_PATH}]..."
36 for f in README License LICENSE Changelog Changelog-last TODO FAQ INSTALL AUTHORS samples; do
37 if [ -r "${f}" ]; then
38 cp -avp "${f}" "${EXPORT_PATH}/"
39 if [ "${BUILD_SDEB}" = "1" ]; then
40 # No need to install the license file
41 if [ "${f}" = "LICENSE" ]; then
42 continue
43 fi
44 echo "${f}" >> debian/docs
45 fi
46 fi
47 done
48 echo
49
50 if [ -d "screenshot" ]; then
51 echo "[*] Copying screenshots..."
52 mkdir -p "${EXPORT_PATH}"
53 cp -vp screenshot/* "${EXPORT_PATH}/"
54 echo
55 fi
56 }
57
58 function duilder_git()
59 {
60 PRJ="${1}"
61 GIT_DEST="${2}"
62 EXPORT_GIT="${3}"
63 GIT_CHANGELOG="${4}"
64 GIT_PUSH="${5}"
65
66 if [ ! -x /usr/bin/git ]; then
67 echo "[*] Warning: Git not found!"
68 exit 0
69 fi
70
71 if [ ! -d .git ]; then
72 echo "[*] Warning: I cannot find .git directory!"
73 exit 0
74 fi
75
76 echo "[*] Testing if a tag is present for HEAD..."
77 D=`git describe | sed -e 's/^.*-g[0-9a-fA-F]*$//'`
78 if [ "${D}" = "" ]; then
79 echo "No annotated tag preset for HEAD! Please add one!"
80 exit 1
81 fi
82
83 if [ "${EXPORT_GIT}" = "1" ]; then
84 echo "[*] Generating GIT tree for HTTP transport..."
85 if [ ! -d "${GIT_DEST}/${PRJ}.git" ]; then
86 git clone --bare . "${GIT_DEST}/${PRJ}.git"
87
88 # Activate post-update hook
89 cp "${GIT_DEST}/${PRJ}.git/hooks/post-update.sample" \
90 "${GIT_DEST}/${PRJ}.git/hooks/post-update"
91 chmod a+x "${GIT_DEST}/${PRJ}.git/hooks/post-update"
92
93 # add project name and description
94 echo "${PRJ}" > "${GIT_DEST}/${PRJ}.git/description"
95
96 # allow export by git daemon?
97 #touch "${GIT_DEST}/${PRJ}.git/git-daemon-export-ok
98 else
99 # --force?
100 echo "Running git push -v --all \"${GIT_DEST}/${PRJ}.git\"..."
101 git push -v --all "${GIT_DEST}/${PRJ}.git"
102 echo "Running git push -v --tags \"${GIT_DEST}/${PRJ}.git\"..."
103 git push -v --tags "${GIT_DEST}/${PRJ}.git"
104 fi
105 (cd "${GIT_DEST}/${PRJ}.git" && git update-server-info)
106 fi
107
108 if [ "${GIT_PUSH}" = "1" ]; then
109 echo "[*] Git push..."
110 git push -v --all
111 fi
112
113 if [ "${GIT_CHANGELOG}" = "1" ]; then
114 echo "[*] Generating Changelog from git..."
115 echo -n > Changelog
116
117 # get the list of tags
118 number_of_tags=0
119 git show-ref --tags -d | grep refs/tags/v > duilder.tmp
120 while read sha1 full_tag; do
121 tag=`echo ${full_tag} | sed -e 's#refs/tags/##' | cut -d'^' -f1`
122 tags[${number_of_tags}]=${tag}
123 tags_commit[${number_of_tags}]=${sha1}
124 number_of_tags=$[${number_of_tags}+1]
125 done < duilder.tmp
126 rm -f duilder.tmp
127
128 # get the list of commits, test if is a tag and do the diff
129 prev=""
130 add=""
131 first=1
132 git log --pretty=oneline | cut -f1 | \
133 while read commit junk; do
134 # test if it is a tag
135 tag=""
136 i=0
137 while [ "${i}" -lt "${number_of_tags}" ]; do
138 if [ "${commit}" = "${tags_commit[${i}]}" ]; then
139 tag="${tags[${i}]}"
140 break
141 fi
142
143 i=$[${i}+1]
144 done
145
146 if [ -z "${tag}" ]; then
147 continue
148 fi
149
150 if [ ! -z "${prev}" ]; then
151 echo "[*] Generating Changelog from ${tag} -> ${prev}..."
152 echo -en "${add}" >> Changelog
153 add="\n"
154 echo "[${tag} -> ${prev}]" >> Changelog
155 git shortlog ${tag}..${prev} | \
156 (IFS=""
157 while read line; do
158 echo " ${line}"
159 done) \
160 >> Changelog
161
162 if [ "${first}" = "1" ]; then
163 echo "[*] Generating Changelog-last..."
164 cp Changelog Changelog-last
165 first=0
166 fi
167 fi
168 prev=${tag}
169 done
170 fi
171 }
172
173 function duilder_srpm()
174 {
175 PRJ="${1}"
176 VER="${2}"
177 EXPORT_PATH="${3}"
178 BUILD_SRPM="${4}"
179 SRPM_DEST="${5}"
180 SRPM_POST_RUN="${6}"
181
182 P="${PRJ}-${VER}"
183
184 if [ "${BUILD_SRPM}" != "1" ]; then
185 exit 0
186 fi
187
188 if [ ! -d "${EXPORT_PATH}" ]; then
189 echo "WARN: ${EXPORT_PATH} does not exists. Creating it..."
190 mkdir -p "${EXPORT_PATH}"
191 fi
192
193 echo "[*] Building SRPM..."
194 rpmbuild -ts "${P}.tar.gz"
195 echo
196
197 PKG="${RPMBUILD}/SRPMS/${P}-${REV}.src.rpm"
198
199 # Run a rpmlint on it
200 if [ -x /usr/bin/rpmlint ]; then
201 echo "[*] RPMlinting..."
202 rpmlint -iv "${PKG}" > rpmlint.out
203 else
204 echo "[*] WARN: rpmlint is missing!"
205 fi
206
207 if [ ! -z "${SRPM_DEST}" ]; then
208 echo "[*] Copying [${PKG}] to [${SRPM_DEST}]..."
209 cp -vp "${PKG}" "${SRPM_DEST}/"
210 fi
211
212 echo "[*] Copying to export dir [${EXPORT_PATH}]..."
213 mkdir -p "${EXPORT_PATH}"
214 cp -vp "${PKG}" "${EXPORT_PATH}/"
215 echo
216
217 if [ -x "${SRPM_POST_RUN}" ]; then
218 echo "[*] Running post SRPM build script [${SRPM_POST_RUN}]..."
219 ${SRPM_POST_RUN} "${PKG}"
220 fi
221 }
222
223 function duilder_sdeb()
224 {
225 PRJ="${1}"
226 VER="${2}"
227 EXPORT_PATH="${3}"
228 BUILD_SDEB="${4}"
229 SDEB_DEST="${5}"
230 SDEB_POST_RUN="${6}"
231
232 P="${PRJ}-${VER}"
233
234 if [ "${BUILD_SDEB}" != "1" ]; then
235 exit 0
236 fi
237
238 if [ ! -d "${EXPORT_PATH}" ]; then
239 echo "WARN: ${EXPORT_PATH} does not exists. Creating it..."
240 mkdir -p "${EXPORT_PATH}"
241 fi
242
243 echo "[*] Copying SDEB..."
244 PKG="${PRJ}_${VER}.orig.tar.gz"
245
246 if [ -n "${SDEB_DEST}" ]; then
247 cp -vp "${P}.tar.gz" "${SDEB_DEST}/${PKG}"
248 fi
249
250 echo "[*] Copying to export dir [${DEB_EXPORT_PATH}]..."
251 mkdir -p "${EXPORT_PATH}"
252 cp -vp "${P}.tar.gz" "${EXPORT_PATH}/${PKG}"
253 echo
254
255 if [ -x "${SDEB_POST_RUN}" ]; then
256 echo "[*] Running post SDEB build script [${SDEB_POST_RUN}]..."
257 ${SDEB_POST_RUN} "${SDEB}/${PKG}"
258 fi
259 }
260
261 function duilder_tar()
262 {
263 PRJ="${1}"
264 VER="${2}"
265 EXPORT_PATH="${3}"
266 EXCLUDE="${4}"
267
268 P="${PRJ}-${VER}"
269
270 if [ ! -d "${EXPORT_PATH}" ]; then
271 echo "[*] WARN: ${EXPORT_PATH} does not exists. Creating it..."
272 mkdir -p "${EXPORT_PATH}"
273 fi
274
275 echo "[*] Generating tarball [${P}.tar.gz]..."
276 ADD_EXCLUDE=""
277 if [ ! -z "${EXCLUDE}" ]; then
278 ADD_EXCLUDE="--exclude-from ${P}/${EXCLUDE}"
279 echo "[*] ADD_EXCLUDE=${ADD_EXCLUDE}"
280 fi
281
282 (cd .. \
283 && rm -rf "${P}" \
284 && cp -a --link "${PRJ}" "${P}" \
285 && tar czf "${PRJ}/${P}.tar.gz" \
286 --exclude-vcs \
287 --exclude ${P}/Makefile \
288 ${ADD_EXCLUDE} \
289 "${P}" \
290 && rm -rf "${P}"
291 )
292
293 echo "[*] Copying source to ${EXPORT_PATH}..."
294 mkdir -p "${EXPORT_PATH}"
295 cp -vp "${P}.tar.gz" "${EXPORT_PATH}/"
296 echo
297 }
298
299 ####################################################################
300
301 # Variables
302 if [ -d "${HOME}/rpmbuild" ]; then
303 RPMBUILD="${HOME}/rpmbuild"
304 else
305 RPMBUILD="/usr/src/redhat"
306 fi
307
308
309 if [ ! -r duilder.conf ]; then
310 echo "[*] You must build a duilder.conf file!"
311 exit 1
312 fi
313
314 source ${PWD}/duilder.conf
315
316 # fixes
317 if [ -z "${GIT_DEST}" ]; then
318 GIT_DEST="${EXPORT_PATH}"
319 fi
320
321 if [ -z "${PRJ}" ]; then
322 echo "ERROR: PRJ= parameter is missing."
323 exit 1
324 fi
325
326 if [ -z "${VER}" ]; then
327 echo "ERROR: VER= parameter is missing."
328 exit 1
329 fi
330
331 if [ -z "${REV}" ]; then
332 echo "ERROR: REV= parameter is missing."
333 exit 1
334 fi
335
336 # export variables - just in case a script cares
337 export PRJ VER REV SHORT_DESCRIPTION EXPORT_PATH EXPORT_GIT GIT_PUSH GIT_DEST
338 export SRPM_DEST SDEB_DEST LICENSE MAINTAINER_NAME MAINTAINER_EMAIL
339 export HOME_PAGE BUILD_SRPM BUILD_SDEB
340
341
342 # Multiplexer
343 if [ "${1}" = "docs" ]; then
344 shift
345 duilder_docs "$@"
346 exit $?
347 fi
348
349 if [ "${1}" = "tar" ]; then
350 shift
351 duilder_tar "$@"
352 exit $?
353 fi
354
355 if [ "${1}" = "git" ]; then
356 shift
357 duilder_git "$@"
358 exit $?
359 fi
360
361 if [ "${1}" = "srpm" ]; then
362 shift
363 duilder_srpm "$@"
364 exit $?
365 fi
366
367 if [ "${1}" = "sdeb" ]; then
368 shift
369 duilder_sdeb "$@"
370 exit $?
371 fi
372
373 if [ "${1}" = "final" ]; then
374 shift
375 duilder_final "$@"
376 exit $?
377 fi
378
379
380 ###### Main stuff
381 echo "[*] Duilder builder script"
382 echo "[*] Copyright Catalin(ux) M. BOIE - catab at embedromix dot ro"
383 echo "[*] PRJ=${PRJ}, VER=${VER}, REV=${REV}"
384 echo "[*] System: `uname -a`"
385 echo "[*] Parameters: ${@}"
386
387 ETC="/etc"
388 BIN="/bin"
389 USR="/usr"
390 USR_BIN="/usr/bin"
391 USR_SBIN="/usr/sbin"
392 USR_INCLUDE="/usr/include"
393 if [ "`uname -m`" = "i686" ]; then
394 USR_LIB="/usr/lib"
395 else
396 USR_LIB="/usr/lib64"
397 fi
398 USR_SHARE="/usr/share"
399 USR_SHARE_DOC="/usr/share/doc/${PRJ}"
400 SBIN="/usr/sbin"
401 VAR="/var"
402 VAR_LIB="/var/lib"
403 MAN="/usr/share/man"
404 PREFIX="/usr"
405
406 while [ "${1}" != "" ]; do
407 xVAR="`echo ${1} | cut -d'=' -f1`"
408 xVAL="`echo ${1} | cut -d'=' -f2 | sed -e "s|\\${prefix}|${PREFIX}|"`"
409 shift
410 case ${xVAR} in
411 --sysconfdir)
412 ETC="${xVAL}"
413 ;;
414 --bindir)
415 USR_BIN="${xVAL}"
416 ;;
417 --sbindir)
418 USR_SBIN="${xVAL}"
419 ;;
420 --includedir)
421 USR_INCLUDE="${xVAL}"
422 ;;
423 --libdir)
424 USR_LIB="${xVAL}"
425 ;;
426 --localstatedir)
427 VAR="${xVAL}"
428 ;;
429 --sharedstatedir)
430 VAR_LIB="${xVAL}"
431 ;;
432 --datadir)
433 USR_SHARE="${xVAL}"
434 ;;
435 --mandir)
436 MAN="${xVAL}"
437 ;;
438 --prefix)
439 PREFIX="${xVAL}"
440 USR="${xVAL}"
441 ;;
442 esac
443 done
444
445 # Last fixes
446 VAR_LOG="${VAR}/log"
447 VAR_RUN="${VAR}/run"
448
449 for i in ETC BIN USR USR_BIN USR_SBIN USR_INCLUDE USR_LIB USR_SHARE USR_SHARE_DOC SBIN VAR VAR_LIB MAN VAR_LOG VAR_RUN; do
450 eval value=\$$i
451 echo "[*] Var ${i}=${value}"
452 done
453
454 # Truncate future sed file
455 > tmp.sed
456
457 DB_SUPPORT=0
458
459 echo -n "[*] Searching for PostgreSQL..."
460 set +e
461 PG_VERSION="`pg_config --version 2>/dev/null`"
462 set -e
463 if [ -z "${PG_VERSION}" ]; then
464 echo " not found."
465 PG_FOUND=0
466 else
467 echo " found version ${PG_VERSION}."
468 PG_FOUND=1
469 PG_INC="-I`pg_config --includedir`"
470 PG_LIB="-L`pg_config --libdir` -lpq"
471
472 echo "s#@PG_VERSION@#${PG_VERSION}#g" >> tmp.sed
473 echo "s#@PG_INC@#${PG_INC}#g" >> tmp.sed
474 echo "s#@PG_LIB@#${PG_LIB}#g" >> tmp.sed
475
476 DB_SUPPORT=1
477 echo "s#@DB_SUPPORT@#${DB_SUPPORT}#g" >> tmp.sed
478 fi
479 echo "s#@PG_FOUND@#${PG_FOUND}#g" >> tmp.sed
480
481
482 echo -n "[*] Searching for MySQL..."
483 set +e
484 MYSQL_VERSION="`mysql_config --version 2>/dev/null`"
485 set -e
486 if [ -z "${MYSQL_VERSION}" ]; then
487 echo " not found."
488 MYSQL_FOUND=0
489 else
490 echo " found version ${MYSQL_VERSION}."
491 MYSQL_FOUND=1
492 MYSQL_INC="`mysql_config --include`"
493 MYSQL_LIB="`mysql_config --libs`"
494
495 echo "s#@MYSQL_VERSION@#${MYSQL_VERSION}#g" >> tmp.sed
496 echo "s#@MYSQL_INC@#${MYSQL_INC}#g" >> tmp.sed
497 echo "s#@MYSQL_LIB@#${MYSQL_LIB}#g" >> tmp.sed
498
499 DB_SUPPORT=1
500 echo "s#@DB_SUPPORT@#${DB_SUPPORT}#g" >> tmp.sed
501 fi
502 echo "s#@MYSQL_FOUND@#${MYSQL_FOUND}#g" >> tmp.sed
503
504 echo -n "[*] Searching for poll..."
505 set +e
506 echo -e "#include <poll.h> \n int main(void) { return poll(0, 0, 0); }" | gcc -x c -pipe - -o /dev/null 2>/dev/null
507 E="${?}"
508 set -e
509 if [ "${E}" != "0" ]; then
510 echo " not found."
511 echo "s#@POLL_FOUND@#0#g" >> tmp.sed
512 else
513 echo " found."
514 echo "s#@POLL_FOUND@#1#g" >> tmp.sed
515 fi
516
517 echo -n "[*] Searching for epoll..."
518 set +e
519 echo -e "#include <sys/epoll.h> \n int main(void) { return epoll_create(64); }" | gcc -x c -pipe - -o /dev/null 2>/dev/null
520 E="${?}"
521 set -e
522 if [ "${E}" != "0" ]; then
523 echo " not found."
524 echo "s#@EPOLL_FOUND@#0#g" >> tmp.sed
525 else
526 echo " found."
527 echo "s#@EPOLL_FOUND@#1#g" >> tmp.sed
528 fi
529
530 echo -n "[*] Searching for ncurses..."
531 set +e
532 echo -e "#include <ncurses.h> \n int main(void) { initscr(); return 0; }" | gcc -x c -pipe - -o /dev/null -lncurses 2>/dev/null
533 E="${?}"
534 set -e
535 if [ "${E}" != "0" ]; then
536 echo " not found."
537 echo "s#@NCURSES_FOUND@#0#g" >> tmp.sed
538 else
539 echo " found."
540 echo "s#@NCURSES_FOUND@#1#g" >> tmp.sed
541 fi
542
543 if [ -n "${CC_SWITCHES}" ]; then
544 _CC_SWITCHES=""
545 echo "[*] Search for valid compiler flags..."
546 add=""
547 for s in ${CC_SWITCHES}; do
548 echo -n " [*] Testing switch [${s}]..."
549 set +e
550 echo "int main(void) { return 0; }" | gcc ${s} -x c -pipe - -o /dev/null 2>/dev/null
551 E=${?}
552 set -e
553 if [ "${E}" != "0" ]; then
554 echo "not supported"
555 else
556 echo "supported"
557 _CC_SWITCHES="${_CC_SWITCHES}${add}${s}"
558 add=" "
559 fi
560 done
561 fi
562
563 # generic stuff
564 echo "s#@PRJ@#${PRJ}#g" >> tmp.sed
565 echo "s#@VER@#${VER}#g" >> tmp.sed
566 echo "s#@REV@#${REV}#g" >> tmp.sed
567 echo "s#@ETC@#${ETC}#g" >> tmp.sed
568 echo "s#@BIN@#${BIN}#g" >> tmp.sed
569 echo "s#@USR@#${USR}#g" >> tmp.sed
570 echo "s#@USR_BIN@#${USR_BIN}#g" >> tmp.sed
571 echo "s#@SBIN@#${SBIN}#g" >> tmp.sed
572 echo "s#@USR_SBIN@#${USR_SBIN}#g" >> tmp.sed
573 echo "s#@VAR@#${VAR}#g" >> tmp.sed
574 echo "s#@VAR_LIB@#${VAR_LIB}#g" >> tmp.sed
575 echo "s#@VAR_LOG@#${VAR_LOG}#g" >> tmp.sed
576 echo "s#@VAR_RUN@#${VAR_RUN}#g" >> tmp.sed
577 echo "s#@USR_INCLUDE@#${USR_INCLUDE}#g" >> tmp.sed
578 echo "s#@USR_INC@#${USR_INCLUDE}#g" >> tmp.sed
579 echo "s#@USR_LIB@#${USR_LIB}#g" >> tmp.sed
580 echo "s#@USR_SHARE@#${USR_SHARE}#g" >> tmp.sed
581 echo "s#@USR_SHARE_DOC@#${USR_SHARE_DOC}#g" >> tmp.sed
582 echo "s#@MAN@#${MAN}#g" >> tmp.sed
583 # Export stuff
584 echo "s#@EXPORT_PATH@#${EXPORT_PATH}#g" >> tmp.sed
585 # cc_switches
586 echo "s#@CC_SWITCHES@#${_CC_SWITCHES}#g" >> tmp.sed
587 echo "s#@MAINTAINER_NAME@#${MAINTAINER_NAME}#g" >> tmp.sed
588 echo "s#@MAINTAINER_EMAIL@#${MAINTAINER_EMAIL}#g" >> tmp.sed
589 echo "s#@SHORT_DESCRIPTION@#${SHORT_DESCRIPTION}#g" >> tmp.sed
590 echo "s#@HOME_PAGE@#${HOME_PAGE}#g" >> tmp.sed
591
592
593
594 if [ -r Makefile.in ]; then
595 echo "[*] Building Makefile..."
596 echo -n > Makefile
597 echo "# duilder header starts #" >> Makefile
598 echo "export PRJ := ${PRJ}" >> Makefile
599 echo "export VER := ${VER}" >> Makefile
600 echo "export REV := ${REV}" >> Makefile
601 echo "export DESTDIR" >> Makefile
602 echo >> Makefile
603 echo "export I_ETC := \$(DESTDIR)${ETC}" >> Makefile
604 echo "export I_BIN := \$(DESTDIR)${BIN}" >> Makefile
605 echo "export I_SBIN := \$(DESTDIR)${SBIN}" >> Makefile
606 echo "export I_USR := \$(DESTDIR)${USR}" >> Makefile
607 echo "export I_USR_BIN := \$(DESTDIR)${USR_BIN}" >> Makefile
608 echo "export I_USR_SBIN := \$(DESTDIR)${USR_SBIN}" >> Makefile
609 echo "export I_USR_INCLUDE := \$(DESTDIR)${USR_INCLUDE}" >> Makefile
610 echo "export I_USR_INC := \$(DESTDIR)${USR_INCLUDE}" >> Makefile
611 echo "export I_USR_SHARE := \$(DESTDIR)${USR_SHARE}" >> Makefile
612 echo "export I_USR_SHARE_DOC := \$(DESTDIR)${USR_SHARE_DOC}" >> Makefile
613 echo "export I_USR_LIB := \$(DESTDIR)${USR_LIB}" >> Makefile
614 echo "export I_LIB := \$(DESTDIR)${USR_LIB}" >> Makefile
615 echo "export I_VAR := \$(DESTDIR)${VAR}" >> Makefile
616 echo "export I_VAR_LIB := \$(DESTDIR)${VAR_LIB}" >> Makefile
617 echo "export I_VAR_LOG := \$(DESTDIR)${VAR_LOG}" >> Makefile
618 echo "export I_VAR_RUN := \$(DESTDIR)${VAR_RUN}" >> Makefile
619 echo "export I_MAN := \$(DESTDIR)${MAN}" >> Makefile
620 echo >> Makefile
621 echo "# DB stuff" >> Makefile
622 echo "export DB_SUPPORT := ${DB_SUPPORT}" >> Makefile
623 echo "# PG" >> Makefile
624 echo "export PG_FOUND := ${PG_FOUND}" >> Makefile
625 echo "export PG_INC := ${PG_INC}" >> Makefile
626 echo "export PG_LIB := ${PG_LIB}" >> Makefile
627 echo "# MySQL" >> Makefile
628 echo "export MYSQL_FOUND := ${MYSQL_FOUND}" >> Makefile
629 echo "export MYSQL_INC := ${MYSQL_INC}" >> Makefile
630 echo "export MYSQL_LIB := ${MYSQL_LIB}" >> Makefile
631 echo >> Makefile
632 echo "# duilder header ends #" >> Makefile
633 echo >> Makefile
634
635 sed -f tmp.sed Makefile.in >> Makefile
636
637 echo >> Makefile
638 echo "# duilder tail starts #" >> Makefile
639 echo >> Makefile
640 echo "# This is to allow exporting only the git tree" >> Makefile
641 echo "dist_git:" >> Makefile
642 echo " @./duilder git \"\$(PRJ)\" \"${GIT_DEST}\" \"${EXPORT_GIT}\" \"${EXPORT_PATH}\" \"${GIT_CHANGELOG}\"" >> Makefile
643 echo >> Makefile
644 echo ".PHONY: dist" >> Makefile
645 echo "dist: clean" >> Makefile
646 echo " @./duilder git \"\$(PRJ)\" \"${GIT_DEST}\" \"${EXPORT_GIT}\" \"${GIT_CHANGELOG}\"" \"${GIT_PUSH}\" >> Makefile
647 echo " @./duilder tar \"\$(PRJ)\" \"\$(VER)\" \"${EXPORT_PATH}\" \"${EXCLUDE}\"" >> Makefile
648 echo " @./duilder srpm \"\$(PRJ)\" \"\$(VER)\" \"${EXPORT_PATH}\" \"${BUILD_SRPM}\" \"${SRPM_DEST}\" \"${SRPM_POST_RUN}\"" >> Makefile
649 echo " @./duilder sdeb \"\$(PRJ)\" \"\$(VER)\" \"${EXPORT_PATH}\" \"${BUILD_SDEB}\" \"${SDEB_DEST}\" \"${SDEB_POST_RUN}\"" >> Makefile
650 echo " @./duilder docs \"\$(PRJ)\" \"\$(VER)\" \"${EXPORT_PATH}\"" >> Makefile
651 echo " @./duilder final \"\$(PRJ)\" \"\$(VER)\" \"${RELEASE_SCRIPT}\"" >> Makefile
652 echo " @rm -f \"\$(PRJ)-\$(VER).tar.gz\"" >> Makefile
653 echo >> Makefile
654 fi
655
656 if [ -r "${PRJ}.spec.in" ]; then
657 echo "[*] Generating .spec file..."
658 sed -f tmp.sed ${PRJ}.spec.in > ${PRJ}.spec
659 fi
660
661 if [ ! -z "${CONFIG_H}" ]; then
662 echo "[*] Generating ${CONFIG_H} file..."
663 sed -f tmp.sed ${CONFIG_H}.in > ${CONFIG_H}
664 fi
665
666 if [ "${BUILD_SDEB}" = "1" ]; then
667 AUTOGENERATE="${AUTOGENERATE} debian/control.in debian/changelog.in"
668 AUTOGENERATE="${AUTOGENERATE} debian/copyright.in debian/rules.in"
669 fi
670
671 echo "[*] Autogenerate files from .in..."
672 for f in ${AUTOGENERATE}; do
673 if [ -r "${f}" ]; then
674 dst="${f%.in}"
675 echo " [*] Autogenerate ${dst} from ${f}..."
676 sed -f tmp.sed "${f}" > "${dst}"
677 # We need to have the same rights (maybe is executable...)
678 chmod --reference="${f}" "${dst}"
679 fi
680 done
681
682 rm -f tmp.sed
683
684 if [ "`basename ${0}`" = "duilderx" ]; then
685 echo "[*] Cloning myself to destination as 'duilder'..."
686 cp -vpf "${0}" ${PWD}/duilder
687 fi
688
689 echo "[*] Done. Run make."
File duilder.conf added (mode: 100644) (index 0000000..1824f10)
1 PRJ="nf2fa"
2 VER="1.0.0"
3 REV="1"
4 EXCLUDE=".exclude"
5 EXPORT_PATH="/data/www/umbrella/kernel/us/nf2fa"
6 EXPORT_GIT="0"
7 GIT_PUSH="0"
8 GIT_CHANGELOG="1"
9 BUILD_SRPM="1"
10 SRPM_DEST="../dinorepo/fedora/SRPMS"
11 SRPM_POST_RUN="/usr/local/bin/submit_package"
12 BUILD_TGZ="1"
13 BUILD_DEB="1"
14
15 CONFIG_H="nf2fa_common.h"
16
17 RELEASE_SCRIPT="./duilder_release"
18 RELEASE_SCRIPT="/usr/local/bin/duilder_release"
19
20 CC_SWITCHES="-O3 -fstack-reuse=all -flto -Wtrampolines -Wl,-z,noexecstack"
21 CC_SWITCHES="${CC_SWITCHES} -Wl,-z,now -Wl,-z,relro -Wl,-O1 -Wl,-z,noexecstack"
22 CC_SWITCHES="${CC_SWITCHES} -fPIE -pie -fstack-protector-all"
23 CC_SWITCHES="${CC_SWITCHES} -Wcast-align -Wformat=2"
24 CC_SWITCHES="${CC_SWITCHES} -Wformat-security -fno-common"
25 CC_SWITCHES="${CC_SWITCHES} -Wmissing-prototypes -Wmissing-declarations"
26 CC_SWITCHES="${CC_SWITCHES} -Wstrict-overflow -Wstrict-prototypes"
27 CC_SWITCHES="${CC_SWITCHES} -D _FORTIFY_SOURCES=2"
28 CC_SWITCHES="${CC_SWITCHES} -fno-guess-branch-probability -fbounds-check"
29 CC_SWITCHES="${CC_SWITCHES} -Wl,-O3 -Wpadded"
30 CC_SWITCHES="${CC_SWITCHES} -ftree-loop-distribution -ftree-vectorize -ftree-loop-if-convert"
31 CC_SWITCHES="${CC_SWITCHES} -ftree-loop-im -ftree-parallelize-loops=4"
32 #CC_SWITCHES="${CC_SWITCHES} -Wconversion"
33
File key.c changed (mode: 100644) (index 07ac839..151c3c5)
12 12
13 13 #include "key.h" #include "key.h"
14 14
15 /*
16 * Print a key structure
17 */
18 void key_print(const struct key *k)
15 static char error[256];
16
17 char *key_error(void)
19 18 { {
20 printf("Key %03hhu name=[%s] itime=%ld key=[%s] ts=%ld ip=[%s]\n",
21 k->id, k->name, k->itime, k->key, k->ts, k->ip);
19 return error;
22 20 } }
23 21
24 22 /* /*
 
... ... int key_save(const unsigned int uid, const struct key *k)
42 40 snprintf(path, sizeof(path), "%s/%u/%03hhu.tmp", snprintf(path, sizeof(path), "%s/%u/%03hhu.tmp",
43 41 KEY_DIR, uid, k->id); KEY_DIR, uid, k->id);
44 42
45 fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC);
43 fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0400);
46 44 if (fd == -1) { if (fd == -1) {
47 printf("Cannot open key file [%s]: %s!\n",
45 snprintf(error, sizeof(error),
46 "cannot open key file [%s]: %s",
48 47 path, strerror(errno)); path, strerror(errno));
49 48 break; break;
50 49 } }
 
... ... int key_save(const unsigned int uid, const struct key *k)
57 56 len = strlen(buf); len = strlen(buf);
58 57 n = write(fd, buf, len); n = write(fd, buf, len);
59 58 if (n != len) { if (n != len) {
60 printf("Cannot write to tmp file %s: %s!\n",
59 snprintf(error, sizeof(error),
60 "cannot write to tmp file %s: %s",
61 61 path, strerror(errno)); path, strerror(errno));
62 62 break; break;
63 63 } }
64 64
65 65 n = fsync(fd); n = fsync(fd);
66 66 if (n == -1) { if (n == -1) {
67 printf("Cannot fsync tmp file: %s!\n",
67 snprintf(error, sizeof(error),
68 "cannot fsync tmp file: %s",
68 69 strerror(errno)); strerror(errno));
69 70 break; break;
70 71 } }
71 72
72 73 n = close(fd); n = close(fd);
73 74 if (n == -1) { if (n == -1) {
74 printf("Cannot close tmp file: %s!\n",
75 snprintf(error, sizeof(error),
76 "cannot close tmp file: %s",
75 77 strerror(errno)); strerror(errno));
76 78 break; break;
77 79 } }
 
... ... int key_save(const unsigned int uid, const struct key *k)
81 83 KEY_DIR, uid, k->id); KEY_DIR, uid, k->id);
82 84 n = rename(path, path2); n = rename(path, path2);
83 85 if (n == -1) { if (n == -1) {
84 printf("Cannot rename tmp file: %s!\n",
86 snprintf(error, sizeof(error),
87 "cannot rename tmp file: %s",
85 88 strerror(errno)); strerror(errno));
86 89 break; break;
87 90 } }
 
... ... int key_load(struct key *k, const unsigned int uid, const unsigned char key_id)
121 124
122 125 fd = open(path, O_RDONLY); fd = open(path, O_RDONLY);
123 126 if (fd == -1) { if (fd == -1) {
124 printf("Cannot open key file [%s]: %s!\n",
127 snprintf(error, sizeof(error),
128 "cannot open key file [%s]: %s",
125 129 path, strerror(errno)); path, strerror(errno));
126 130 break; break;
127 131 } }
128 132
129 133 n = read(fd, buf, sizeof(buf)); n = read(fd, buf, sizeof(buf));
130 134 if (n == -1) { if (n == -1) {
131 printf("Cannot read from file %s: %s!\n",
135 snprintf(error, sizeof(error),
136 "cannot read from file %s: %s",
132 137 path, strerror(errno)); path, strerror(errno));
133 138 break; break;
134 139 } }
 
... ... int key_load(struct key *k, const unsigned int uid, const unsigned char key_id)
179 184 int key_remove(const unsigned int uid, const unsigned char id) int key_remove(const unsigned int uid, const unsigned char id)
180 185 { {
181 186 char path[256]; char path[256];
187 struct stat s;
188 int r;
182 189
183 190 snprintf(path, sizeof(path), "%s/%u/%03hhu", KEY_DIR, uid, id); snprintf(path, sizeof(path), "%s/%u/%03hhu", KEY_DIR, uid, id);
184 return unlink(path);
191
192 r = stat(path, &s);
193 if (r == -1) {
194 snprintf(error, sizeof(error),
195 "key not found");
196 return -1;
197 }
198
199 r = unlink(path);
200 if (r == -1) {
201 snprintf(error, sizeof(error),
202 "cannot remove key: %s", strerror(errno));
203 return -1;
204 }
205
206 return 0;
185 207 } }
File key.h changed (mode: 100644) (index a5dac1e..4642b72)
... ... struct key
4 4 { {
5 5 time_t itime; time_t itime;
6 6 time_t ts; time_t ts;
7 unsigned char id;
8 7 char name[32]; char name[32];
9 8 char key[32]; char key[32];
9 unsigned char id;
10 10 char ip[40]; char ip[40];
11 unsigned char pad[7];
11 12
12 13 struct key *next; struct key *next;
13 14 }; };
14 15
15 16
16 void key_print(const struct key *k);
17 char *key_error(void);
17 18 int key_save(const unsigned int uid, const struct key *k); int key_save(const unsigned int uid, const struct key *k);
18 19 int key_load(struct key *k, const unsigned int uid, int key_load(struct key *k, const unsigned int uid,
19 20 const unsigned char key_id); const unsigned char key_id);
File nf-queue.c deleted (index 1420273..0000000)
1 /*
2 * src/nf-log.c Monitor netfilter queue events
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
7 * of the License.
8 *
9 * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net>
10 */
11
12 #include <sys/types.h>
13 #include <linux/netfilter.h>
14 #include <linux/netfilter/nfnetlink_queue.h>
15
16 #include "utils.h"
17 #include <netlink/netfilter/nfnl.h>
18 #include <netlink/netfilter/queue.h>
19 #include <netlink/netfilter/queue_msg.h>
20
21 static struct nl_handle *nfnlh;
22
23 static void obj_input(struct nl_object *obj, void *arg)
24 {
25 struct nfnl_queue_msg *msg = (struct nfnl_queue_msg *) obj;
26 struct nl_dump_params dp = {
27 .dp_type = NL_DUMP_STATS,
28 .dp_fd = stdout,
29 .dp_dump_msgtype = 1,
30 };
31
32 nfnl_queue_msg_set_verdict(msg, NF_ACCEPT);
33 nl_object_dump(obj, &dp);
34 nfnl_queue_msg_send_verdict(nfnlh, msg);
35 }
36
37 static int event_input(struct nl_msg *msg, void *arg)
38 {
39 if (nl_msg_parse(msg, &obj_input, NULL) < 0)
40 fprintf(stderr, "<<EVENT>> Unknown message type\n");
41
42 /* Exit nl_recvmsgs_def() and return to the main select() */
43 return NL_STOP;
44 }
45
46 int main(int argc, char *argv[])
47 {
48 struct nl_handle *rtnlh;
49 struct nl_cache *link_cache;
50 struct nfnl_queue *queue;
51 enum nfnl_queue_copy_mode copy_mode;
52 uint32_t copy_range;
53 int err = 1;
54 int family;
55
56 if (nltool_init(argc, argv) < 0)
57 return -1;
58
59 nfnlh = nltool_alloc_handle();
60 if (nfnlh == NULL)
61 return -1;
62
63 nl_disable_sequence_check(nfnlh);
64
65 nl_socket_modify_cb(nfnlh, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
66
67 if ((argc > 1 && !strcasecmp(argv[1], "-h")) || argc < 3) {
68 printf("Usage: nf-queue family group [ copy_mode ] "
69 "[ copy_range ]\n");
70 return 2;
71 }
72
73 if (nfnl_connect(nfnlh) < 0) {
74 fprintf(stderr, "%s\n", nl_geterror());
75 goto errout;
76 }
77
78 family = nl_str2af(argv[1]);
79 if (family == AF_UNSPEC) {
80 fprintf(stderr, "Unknown family: %s\n", argv[1]);
81 goto errout;
82 }
83
84 nfnl_queue_pf_unbind(nfnlh, family);
85 if (nfnl_queue_pf_bind(nfnlh, family) < 0) {
86 fprintf(stderr, "%s\n", nl_geterror());
87 goto errout;
88 }
89
90 queue = nfnl_queue_alloc();
91 if (queue == NULL) {
92 fprintf(stderr, "%s\n", nl_geterror());
93 goto errout;
94 }
95
96 nfnl_queue_set_group(queue, atoi(argv[2]));
97
98 copy_mode = NFNL_QUEUE_COPY_PACKET;
99 if (argc > 3) {
100 copy_mode = nfnl_queue_str2copy_mode(argv[3]);
101 if (copy_mode < 0) {
102 fprintf(stderr, "%s\n", nl_geterror());
103 goto errout;
104 }
105 }
106 nfnl_queue_set_copy_mode(queue, copy_mode);
107
108 copy_range = 0xFFFF;
109 if (argc > 4)
110 copy_range = atoi(argv[4]);
111 nfnl_queue_set_copy_range(queue, copy_range);
112
113 if (nfnl_queue_create(nfnlh, queue) < 0) {
114 fprintf(stderr, "%s\n", nl_geterror());
115 goto errout;
116 }
117
118 rtnlh = nltool_alloc_handle();
119 if (rtnlh == NULL) {
120 goto errout_close;
121 }
122
123 if (nl_connect(rtnlh, NETLINK_ROUTE) < 0) {
124 fprintf(stderr, "%s\n", nl_geterror());
125 goto errout;
126 }
127
128 if ((link_cache = rtnl_link_alloc_cache(rtnlh)) == NULL) {
129 fprintf(stderr, "%s\n", nl_geterror());
130 goto errout_close;
131 }
132
133 nl_cache_mngt_provide(link_cache);
134
135 while (1) {
136 fd_set rfds;
137 int nffd, rtfd, maxfd, retval;
138
139 FD_ZERO(&rfds);
140
141 maxfd = nffd = nl_socket_get_fd(nfnlh);
142 FD_SET(nffd, &rfds);
143
144 rtfd = nl_socket_get_fd(rtnlh);
145 FD_SET(rtfd, &rfds);
146 if (maxfd < rtfd)
147 maxfd = rtfd;
148
149 /* wait for an incoming message on the netlink socket */
150 retval = select(maxfd+1, &rfds, NULL, NULL, NULL);
151
152 if (retval) {
153 if (FD_ISSET(nffd, &rfds))
154 nl_recvmsgs_default(nfnlh);
155 if (FD_ISSET(rtfd, &rfds))
156 nl_recvmsgs_default(rtnlh);
157 }
158 }
159
160 nl_cache_mngt_unprovide(link_cache);
161 nl_cache_free(link_cache);
162
163 nfnl_queue_put(queue);
164
165 nl_close(rtnlh);
166 nl_handle_destroy(rtnlh);
167 errout_close:
168 nl_close(nfnlh);
169 nl_handle_destroy(nfnlh);
170 errout:
171 return err;
172 }
File nf2fa.conf.sample added (mode: 100644) (index 0000000..9ee569e)
1 # This is the configuration file for nf2fa daemon
2
3 # What users are allowed to enroll
4 #allow = user1 user2 user3
5
6 # Queue number (base 10 or base 16; 16 bits)
7 # It must match your iptables rules.
8 # Default: 4444
9 #queue = 0x4444
10 #queue = 65000
11 queue = 4444
12
13 # Number of bad entries slots.
14 # This is used to prevent brute force attacks.
15 # Choose a bigger value if you have a fat pipe to Internet.
16 # Default: 4096
17 #bad entries = 4096
18
19 # Socket whre the daemon will listen
20 # Default: /run/nf2fa.sock
21 #sock = /run/nf2fa.sock
22
23 # How much time to grant access, in seconds
24 # Default: 3600
25 #grant time = 3600
File nf2fa.spec.in added (mode: 100644) (index 0000000..b31805f)
1 Summary: Two-factor authentication meets port knocking
2 Name: @PRJ@
3 Version: @VER@
4 Release: @REV@
5 License: GPLv3+
6 Group: Applications/Internet
7 Source: http://kernel.embedromix.ro/us/nf2fa/%{name}-%{version}.tar.gz
8 URL: http://kernel.embedromix.ro/us/
9 BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
10 BuildRequires: make, gcc, openssl-devel, libnetfilter_queue-devel
11 BuildRequires: libmnl-devel, qrencode-devel
12 Requires: openssl-libs, libnetfilter_queue, libmnl, qrencode-libs
13
14 %global _hardened_build 1
15
16 %description
17 Open firewall from an IP using two-factor authentication (2fa).
18
19 %prep
20 %setup -q
21
22 %build
23 %configure
24 make
25
26 %install
27 rm -rf ${RPM_BUILD_ROOT}
28 mkdir -p ${RPM_BUILD_ROOT}
29 make install DESTDIR=${RPM_BUILD_ROOT}
30
31 %clean
32 rm -rf ${RPM_BUILD_ROOT}
33
34 %files
35 %attr (-,root,root)
36 %{_sbindir}/nf2fad
37 %{_bindir}/nf2fac
38 %doc README Changelog
39
40 %changelog
41 * Sun Feb 11 2018 Catalin(ux) M. BOIE <catab at embedromix dot ro> 1.0.0
42 First release
File nf2fa_common.h.in renamed from nf2fa_common.h (similarity 68%) (mode: 100644) (index 0ff150b..be8b674)
1 #define NF2FA_VERSION "@VER@"
2
1 3 #define NF2FA_CMD_ENROLL 0 #define NF2FA_CMD_ENROLL 0
2 4 #define NF2FA_CMD_LIST 1 #define NF2FA_CMD_LIST 1
3 5 #define NF2FA_CMD_UNENROLL 2 #define NF2FA_CMD_UNENROLL 2
4
5 #define SOCKET_NAME "/run/nf2fa.sock"
File nf2fac.c changed (mode: 100644) (index cc8fdaa..b070c4f)
22 22 #include "key.h" #include "key.h"
23 23 #include "protocol.h" #include "protocol.h"
24 24
25 static char *sock_path = "/etc/nf2fa.sock";
26
25 27 static void help(void) static void help(void)
26 28 { {
27 29 printf("Usage: nf2afc <command> [options]\n"); printf("Usage: nf2afc <command> [options]\n");
 
... ... static void help(void)
33 35
34 36 int main(int argc, char *argv[]) int main(int argc, char *argv[])
35 37 { {
36 unsigned char buf[8 * 4096], len;
38 unsigned char buf[8 * 4096];
37 39 int sock; int sock;
38 40 struct sockaddr_un sa_un; struct sockaddr_un sa_un;
39 41 socklen_t slen; socklen_t slen;
 
... ... int main(int argc, char *argv[])
41 43 unsigned short i; unsigned short i;
42 44 unsigned char cmd, err; unsigned char cmd, err;
43 45 struct key k; struct key k;
46 char *s;
44 47
45 48 if (argc < 2) { if (argc < 2) {
46 49 help(); help();
47 50 return 1; return 1;
48 51 } }
49 52
53 s = getenv("NF2FA_SOCK");
54 if (s)
55 sock_path = s;
56
50 57 i = 0; i = 0;
51 58 if (strcmp(argv[1], "enroll") == 0) { if (strcmp(argv[1], "enroll") == 0) {
52 59 if (argc < 3) { if (argc < 3) {
 
... ... int main(int argc, char *argv[])
61 68 } else if (strcmp(argv[1], "list") == 0) { } else if (strcmp(argv[1], "list") == 0) {
62 69 buf[i++] = NF2FA_CMD_LIST; buf[i++] = NF2FA_CMD_LIST;
63 70 } else if (strcmp(argv[1], "unenroll") == 0) { } else if (strcmp(argv[1], "unenroll") == 0) {
71 unsigned char id;
72 char sid[4];
73
64 74 if (argc < 3) { if (argc < 3) {
65 75 help(); help();
66 76 return 1; return 1;
67 77 } }
68 78
79 id = strtoul(argv[2], NULL, 10);
80 sprintf(sid, "%03hhu", id);
81 if (strcmp(sid, argv[2]) != 0) {
82 fprintf(stderr,
83 "Error: Invalid id! Must be XXX (0 <= X <= 9)\n");
84 return 1;
85 }
69 86 buf[i++] = NF2FA_CMD_UNENROLL; buf[i++] = NF2FA_CMD_UNENROLL;
70 buf[i++] = strtoul(argv[2], NULL, 10);
87 buf[i++] = id;
71 88 } else { } else {
72 printf("Unknown command!\n");
89 fprintf(stderr, "Error: unknown command!\n");
90 help();
73 91 return 1; return 1;
74 92 } }
75 93
76 94 sock = socket(AF_UNIX, SOCK_STREAM, 0); sock = socket(AF_UNIX, SOCK_STREAM, 0);
77 95 if (sock == -1) { if (sock == -1) {
78 printf("Cannot create unix socket: %s!\n", strerror(errno));
96 fprintf(stderr, "Error: cannot create unix socket: %s!\n",
97 strerror(errno));
79 98 return 1; return 1;
80 99 } }
81 100 memset(&sa_un, 0, sizeof(struct sockaddr_un)); memset(&sa_un, 0, sizeof(struct sockaddr_un));
82 101 sa_un.sun_family = AF_UNIX; sa_un.sun_family = AF_UNIX;
83 strncpy(sa_un.sun_path, SOCKET_NAME, sizeof(sa_un.sun_path) - 1);
102 strncpy(sa_un.sun_path, sock_path, sizeof(sa_un.sun_path) - 1);
84 103 slen = sizeof(struct sockaddr_un); slen = sizeof(struct sockaddr_un);
85 104
86 105 n = connect(sock, (struct sockaddr *) &sa_un, slen); n = connect(sock, (struct sockaddr *) &sa_un, slen);
87 106 if (n == -1) { if (n == -1) {
88 printf("Cannot connect: %s!\n", strerror(errno));
107 fprintf(stderr, "Error: cannot connect: %s!\n", strerror(errno));
89 108 return 1; return 1;
90 109 } }
91 110
92 111 n = send(sock, buf, i, 0); n = send(sock, buf, i, 0);
93 112 if (n == -1) { if (n == -1) {
94 printf("Cannot send: %s!\n", strerror(errno));
113 fprintf(stderr, "Error: cannot send: %s!\n", strerror(errno));
95 114 return 1; return 1;
96 115 } }
97 116
98 117 n = recv(sock, buf, sizeof(buf), 0); n = recv(sock, buf, sizeof(buf), 0);
99 118 if (n == -1) { if (n == -1) {
100 printf("Cannot receive: %s!\n", strerror(errno));
119 fprintf(stderr, "Error: cannot receive: %s!\n", strerror(errno));
120 return 1;
121 }
122 if (n == 0) {
123 fprintf(stderr, "Error: server unexpectedly closed the connection.\n");
124 return 1;
125 }
126 if (n < 2) {
127 fprintf(stderr, "Error: server sent partial data.\n");
101 128 return 1; return 1;
102 129 } }
103 130
104 131 close(sock); close(sock);
105 132
106 printf("DEBUG: Received:\n");
107 dump(buf, n);
133 //printf("DEBUG: Received:\n");
134 //dump(buf, n);
108 135
109 136 i = 0; i = 0;
110 137 cmd = buf[i++]; n--; cmd = buf[i++]; n--;
111 138 err = buf[i++]; n--; err = buf[i++]; n--;
112 139
113 if (err != 0x00) {
140 while (err != 0x00) {
114 141 char error[64]; char error[64];
142 unsigned char len, len2;
115 143
116 144 len = buf[i++]; n--; len = buf[i++]; n--;
117 memcpy(error, buf + i, len);
118 error[len] = '\0';
119 printf("ERROR: %s!\n", error);
145 if (len > n)
146 break;
147 if (len > sizeof(error) - 1)
148 len2 = sizeof(error) - 1;
149 else
150 len2 = len;
151 memcpy(error, buf + i, len2);
152 error[len2] = '\0';
153 i += len; n -= len;
154
155 fprintf(stderr, "Error: %s!\n", error);
120 156 return 1; return 1;
121 157 } }
122 158
123 if (cmd == NF2FA_CMD_ENROLL) {
159 while (cmd == NF2FA_CMD_ENROLL) {
124 160 char info[128]; char info[128];
125 unsigned char id;
161 unsigned char id, len, len2;
162 int r;
163
164 if (n < 2)
165 break;
166
167 id = buf[i++]; n--;
168 len = buf[i++]; n--;
169 if (len > n)
170 break;
171 if (len > sizeof(k.key) - 1)
172 len2 = sizeof(k.key) - 1;
173 else
174 len2 = len;
175 memcpy(k.key, buf + i, len2);
176 k.key[len2] = '\0';
177 i += len; n -= len;
126 178
127 id = buf[i++];
128 len = buf[i++];
129 memcpy(k.key, buf + i, len); i += len;
130 k.key[len] = '\0';
131 179 printf("Key is %s (id %03hhu). Scan the QR code or type the key.\n", printf("Key is %s (id %03hhu). Scan the QR code or type the key.\n",
132 180 k.key, id); k.key, id);
133 181 snprintf(info, sizeof(info), "%s - id %03hhu", k.name, id); snprintf(info, sizeof(info), "%s - id %03hhu", k.name, id);
134 totp_text(k.key, info);
182 r = totp_text(k.key, info);
183 if (r != 0) {
184 fprintf(stderr, "Error: %s\n", totp_error());
185 return 1;
186 }
135 187 return 0; return 0;
136 188 } }
137 189
138 if (cmd == NF2FA_CMD_LIST) {
190 while (cmd == NF2FA_CMD_LIST) {
191 int err = 1;
192
139 193 if (n == 0) { if (n == 0) {
140 194 printf("No enrollments.\n"); printf("No enrollments.\n");
141 195 return 0; return 0;
142 196 } }
143 197
144 printf("No Last used Last IP"
145 " Name\n");
146 while (n > 0) {
198 printf("No Enroll time Name\n");
199 while (1) {
147 200 struct key k; struct key k;
148 201 unsigned int x; unsigned int x;
149 char t[32];
202 char t[32], itime[32];
150 203 struct tm tm; struct tm tm;
204 unsigned char len, len2;
205
206 if (n == 0) {
207 err = 0;
208 break;
209 }
151 210
152 211 k.id = buf[i++]; n--; k.id = buf[i++]; n--;
153 212
154 213 len = buf[i++]; n--; len = buf[i++]; n--;
155 memcpy(k.name, buf + i, len); i += len; n -= len;
156 k.name[len] = '\0';
214 if (len > n)
215 break;
216 if (len > sizeof(k.name) - 1)
217 len2 = sizeof(k.name) - 1;
218 else
219 len2 = len;
220 memcpy(k.name, buf + i, len2);
221 k.name[len2] = '\0';
222 i += len; n -= len;
157 223
158 memcpy(&x, buf + i, 4); i += 4; n -= 4;
224 if (n < 4)
225 break;
226 memcpy(&x, buf + i, 4);
159 227 k.ts = ntohl(x); k.ts = ntohl(x);
228 i += 4; n -= 4;
160 229
230 if (n < 4)
231 break;
232 memcpy(&x, buf + i, 4); i += 4; n -= 4;
233 k.itime = ntohl(x);
234
235 if (n < 1)
236 break;
161 237 len = buf[i++]; n--; len = buf[i++]; n--;
162 memcpy(k.ip, buf + i, len); i += len; n -= len;
163 k.ip[len] = '\0';
238 if (len > n)
239 break;
240 if (len > sizeof(k.ip) - 1)
241 len2 = sizeof(k.ip) - 1;
242 else
243 len2 = len;
244 memcpy(k.ip, buf + i, len2);
245 k.ip[len2] = '\0';
246 i += len; n -= len;
164 247
248 // show
165 249 if (k.ts == 0) { if (k.ts == 0) {
166 250 sprintf(t, "%-14s", "not used"); sprintf(t, "%-14s", "not used");
167 251 } else { } else {
168 252 localtime_r(&k.ts, &tm); localtime_r(&k.ts, &tm);
169 strftime(t, sizeof(t), "%D %H:%M", &tm);
253 strftime(t, sizeof(t), "%F %H:%M", &tm);
170 254 } }
171 printf("%03hhu %s %-39s %s\n",
172 k.id, t, k.ip, k.name);
255 localtime_r(&k.itime, &tm);
256 strftime(itime, sizeof(itime), "%F %H:%M", &tm);
257 printf("%03hhu %s %s\n", k.id, itime, k.name);
258 if (k.ts)
259 printf(" Last access from IP %s on %s\n",
260 k.ip, t);
173 261 } }
262 if (err)
263 break;
264
174 265 return 0; return 0;
175 266 } }
176 267
177 if (cmd == NF2FA_CMD_UNENROLL) {
268 while (cmd == NF2FA_CMD_UNENROLL) {
178 269 printf("Successfully un-enrolled.\n"); printf("Successfully un-enrolled.\n");
179 270 return 0; return 0;
180 271 } }
181 272
182 printf("Unknown answer [0x%02hhx]!\n", buf[0]);
273 fprintf(stderr, "Unknown or broken answer [0x%02hhx]!\n", buf[0]);
183 274 return 1; return 1;
184 275 } }
File nf2fad.c changed (mode: 100644) (index c7b5814..ca35560)
1 1 /* /*
2 2 * Based on http://www.netfilter.org/projects/libnetfilter_queue/doxygen/html/nf-queue_8c_source.html * Based on http://www.netfilter.org/projects/libnetfilter_queue/doxygen/html/nf-queue_8c_source.html
3 * Based on https://code.woboq.org/linux/linux/net/netfilter/nfnetlink_queue.c.html
3 4 * Based on libmnl example. * Based on libmnl example.
4 5 * Author: Catalin(ux) M. BOIE * Author: Catalin(ux) M. BOIE
5 6 */ */
 
27 28 #include <sys/epoll.h> #include <sys/epoll.h>
28 29 #include <sys/stat.h> #include <sys/stat.h>
29 30 #include <sys/un.h> #include <sys/un.h>
31 #include <sys/capability.h>
32 #include <grp.h>
33 #include <pwd.h>
30 34 #include <arpa/inet.h> #include <arpa/inet.h>
31 35 #include <netinet/ip.h> #include <netinet/ip.h>
32 36 #include <netinet/ip6.h> #include <netinet/ip6.h>
 
43 47
44 48 #include "nf2fa_common.h" #include "nf2fa_common.h"
45 49 #include "util.h" #include "util.h"
50 #include "conf.h"
46 51 #include "totp.h" #include "totp.h"
47 52 #include "key.h" #include "key.h"
48 53 #include "protocol.h" #include "protocol.h"
54 #include "brute.h"
49 55
50 56 /* Keep track of IP and expiration */ /* Keep track of IP and expiration */
51 #define MAX_IPS 128
57 #define MAX_IPS 1024
52 58 struct my_ip struct my_ip
53 59 { {
54 60 unsigned char src[16]; unsigned char src[16];
55 61 unsigned char src_len; unsigned char src_len;
62 unsigned char pad[3];
56 63 unsigned int expire; /* when we should invalidate this IP */ unsigned int expire; /* when we should invalidate this IP */
57 64 }; };
58 65 static struct my_ip my_ips[MAX_IPS]; static struct my_ip my_ips[MAX_IPS];
 
... ... static struct my_ip my_ips[MAX_IPS];
61 68 struct user struct user
62 69 { {
63 70 unsigned int uid; unsigned int uid;
71 unsigned char pad[4];
64 72 struct key *head, *tail; struct key *head, *tail;
65 73 struct user *next; struct user *next;
66 74 }; };
 
... ... static struct nlmsghdr *nfq_hdr_put(unsigned char *buf, const int type,
83 91 return nlh; return nlh;
84 92 } }
85 93
86 static void send_verdict(const int queue_num, const uint32_t id,
94 static int send_verdict(const int queue_num, const uint32_t id,
87 95 const int verdict) const int verdict)
88 96 { {
89 97 unsigned char buf[MNL_SOCKET_BUFFER_SIZE]; unsigned char buf[MNL_SOCKET_BUFFER_SIZE];
 
... ... static void send_verdict(const int queue_num, const uint32_t id,
92 100 nlh = nfq_hdr_put(buf, NFQNL_MSG_VERDICT, queue_num); nlh = nfq_hdr_put(buf, NFQNL_MSG_VERDICT, queue_num);
93 101 nfq_nlmsg_verdict_put(nlh, id, verdict); nfq_nlmsg_verdict_put(nlh, id, verdict);
94 102 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
95 perror("mnl_socket_send");
96 exit(EXIT_FAILURE);
103 xlog("mnl_socket_send send_verdict: %s\n", strerror(errno));
104 return -1;
97 105 } }
106
107 return 0;
98 108 } }
99 109
100 110 /* /*
101 111 * Try to find the code inside the packet * Try to find the code inside the packet
102 * Returns 1 if ok
112 * Returns 0 if not ok, else, the command
103 113 */ */
104 114 static int test_2fa(const unsigned char *data, const unsigned int data_len, static int test_2fa(const unsigned char *data, const unsigned int data_len,
105 115 const unsigned int now, const char *ip) const unsigned int now, const char *ip)
106 116 { {
107 unsigned short i, j;
117 unsigned short i, j, last_tested;
108 118 unsigned int now30; unsigned int now30;
109 unsigned char c;
119 unsigned char c, cmd;
110 120 struct user *q; struct user *q;
111 121 struct key *k; struct key *k;
112 122 char pin[7]; char pin[7];
 
... ... static int test_2fa(const unsigned char *data, const unsigned int data_len,
114 124
115 125 now30 = now / 30; now30 = now / 30;
116 126
117 for (i = 0; i < data_len - (3 - 1); i++) {
127 xlog("DEBUG: %s: %s\n", __func__, ip);
128 dump(data, data_len);
129
130 last_tested = 0xFFFF;
131 for (i = 0; i < data_len - (5 - 1); i++) {
132 if (data[i] != 0xAA)
133 continue;
134
135 // We do not want to check all clones
136 if ((last_tested != 0xFFFF) && (memcmp(data + last_tested, data + i, 3) == 0))
137 continue;
138
118 139 for (j = 0; j < 3; j++) { for (j = 0; j < 3; j++) {
119 c = data[i + j];
140 c = data[i + 1 + j];
120 141 if (((c & 0xF) > 9) || ((c >> 4) > 9)) if (((c & 0xF) > 9) || ((c >> 4) > 9))
121 142 break; break;
122 143 } }
123 144 if (j != 3) // not found if (j != 3) // not found
124 145 continue; continue;
125 146
147 last_tested = i;
126 148 snprintf(pin, sizeof(pin), "%02hhx%02hhx%02hhx", snprintf(pin, sizeof(pin), "%02hhx%02hhx%02hhx",
127 data[i], data[i + 1], data[i + 2]);
128 printf("DEBUG: Packet pin: %s\n", pin);
149 data[i + 1], data[i + 2], data[i + 3]);
150 cmd = data[i + 4];
151 xlog("DEBUG: Packet pin: %s cmd=0x%02hhx\n", pin, cmd);
152
153 if (cmd == 0x11) { // 0x11 = open
154 // do nothing
155 } else if (cmd == 0xcc) { // 0xcc = close
156 // do nothing
157 } else {
158 continue; // invalid command, search again
159 }
129 160
130 161 q = users_head; q = users_head;
131 162 while (q) { while (q) {
132 163 k = q->head; k = q->head;
133 164 while (k) { while (k) {
134 165 r = totp_verify(k->key, now30, k->ts / 30, pin); r = totp_verify(k->key, now30, k->ts / 30, pin);
135 if (r == 1) {
136 printf(" DEBUG: uid %u key %03hhu matched!\n", q->uid, k->id);
137 k->ts = now;
166 if (r != 1) {
167 k = k->next;
168 continue;
169 }
170
171 k->ts = now;
172
173 switch (cmd) {
174 case 0x11: // open
138 175 snprintf(k->ip, sizeof(k->ip), "%s", ip); snprintf(k->ip, sizeof(k->ip), "%s", ip);
139 key_save(q->uid, k);
140 return 1;
176 // TODO: maybe we shoul not allow access if we cannot save key? But it is saved in memory!
177 xlog("%s: uid %u: key %03hhu: authorized\n",
178 ip, q->uid, k->id);
179 break;
180
181 case 0xcc: // close
182 xlog("%s: uid %u: key %03hhu: closed the firewall\n",
183 ip, q->uid, k->id);
184 break;
185
186 default:
187 return cmd;
141 188 } }
142 189
143 k = k->next;
190 key_save(q->uid, k);
191 return cmd;
144 192 } }
145 193
146 194 q = q->next; q = q->next;
 
... ... static int test_2fa(const unsigned char *data, const unsigned int data_len,
152 200
153 201 /* /*
154 202 * Check if IP is in the list (1 if found) * Check if IP is in the list (1 if found)
155 * Returns the position in @pos
203 * Returns 1 if ok
204 * Returns 0 if not found
156 205 */ */
157 206 static int check_ip(const unsigned char *src, const unsigned int src_len, static int check_ip(const unsigned char *src, const unsigned int src_len,
158 207 unsigned int *pos, const struct timeval *now) unsigned int *pos, const struct timeval *now)
 
... ... static int check_ip(const unsigned char *src, const unsigned int src_len,
185 234 * @pos - Position where we shoud store the new entry * @pos - Position where we shoud store the new entry
186 235 */ */
187 236 static void add_ip(const unsigned int pos, const unsigned char *src, static void add_ip(const unsigned int pos, const unsigned char *src,
188 const unsigned char src_len, const struct timeval *now)
237 const unsigned char src_len, const time_t now)
189 238 { {
190 239 unsigned int j; unsigned int j;
191 240
 
... ... static void add_ip(const unsigned int pos, const unsigned char *src,
199 248 break; break;
200 249 } }
201 250
202 if (my_ips[i].expire > now->tv_sec) {
251 if (my_ips[i].expire > now) {
203 252 j = i; j = i;
204 253 break; break;
205 254 } }
 
... ... static void add_ip(const unsigned int pos, const unsigned char *src,
207 256 } }
208 257
209 258 if (j == 0xFFFFFFFF) { if (j == 0xFFFFFFFF) {
210 printf("We could not find a free slot!"
211 " The accept will not be permanent\n");
259 xlog("We could not find a free slot"
260 "; the accept will not be permanent.\n");
212 261 return; return;
213 262 } }
214 263
215 264 memcpy(my_ips[j].src, src, src_len); memcpy(my_ips[j].src, src, src_len);
216 265 my_ips[j].src_len = src_len; my_ips[j].src_len = src_len;
217 my_ips[j].expire = now->tv_sec + 3600;
266 my_ips[j].expire = now + grant_time;
218 267 } }
219 268
220 269 /* /*
 
... ... static unsigned int process(const unsigned short eth,
226 275 struct iphdr *iph; struct iphdr *iph;
227 276 const unsigned char *data; const unsigned char *data;
228 277 unsigned char src[16]; unsigned char src[16];
229 unsigned int data_len, src_len, verdict = NF_DROP;
278 unsigned int data_len, src_len;
230 279 struct timeval now; struct timeval now;
231 280 unsigned int pos = 0xFFFFFFFF; unsigned int pos = 0xFFFFFFFF;
232 281 int r, af; int r, af;
 
... ... static unsigned int process(const unsigned short eth,
235 284 switch (eth) { switch (eth) {
236 285 case ETH_P_IP: case ETH_P_IP:
237 286 iph = (struct iphdr *) p; iph = (struct iphdr *) p;
238 data = p + iph->ihl * 4;
239 data_len = len - iph->ihl * 4;
287 data = p + iph->ihl * 4 + 8;
288 data_len = len - (data - p);
240 289 memcpy(src, p + 12, 4); src_len = 4; memcpy(src, p + 12, 4); src_len = 4;
241 290 af = AF_INET; af = AF_INET;
242 291 break; break;
243 292
244 293 case ETH_P_IPV6: case ETH_P_IPV6:
245 data = p + 40;
246 data_len = len - 40;
294 data = p + 40 + 4;
295 data_len = len - (data - p);
247 296 memcpy(src, p + 8, 16); src_len = 16; memcpy(src, p + 8, 16); src_len = 16;
248 297 af = AF_INET6; af = AF_INET6;
249 298 break; break;
250 299
251 default: return verdict;
300 default: return NF_DROP;
252 301 } }
253 302
254 printf("src: "); dump(src, src_len);
255 dump(data, data_len);
303 //xlog("DEBUG: src: "); dump(src, src_len);
304 //xlog("DEBUG: packet: "); dump(data, data_len);
305 inet_ntop(af, src, ip, sizeof(ip));
306 //xlog("DEBUG: ip=%s\n", ip);
256 307
257 308 gettimeofday(&now, NULL); gettimeofday(&now, NULL);
258 309
259 310 // Checking if the IP is already in the whitelist // Checking if the IP is already in the whitelist
260 311 r = check_ip(src, src_len, &pos, &now); r = check_ip(src, src_len, &pos, &now);
261 312 if (r == 1) { if (r == 1) {
262 printf("\tGive access because already in list!\n");
263 my_ips[pos].expire = now.tv_sec + 3600; // TODO: configurable if we want to do it
264 return NF_ACCEPT;
313 //xlog("\t%s: ip is in the white list.\n", ip);
314
315 r = test_2fa(data, data_len, now.tv_sec, ip);
316 if (r == 0xcc) {
317 xlog("\t%s: User removed from list.\n", ip);
318 my_ips[pos].src_len = 0;
319 return NF_ACCEPT;
320 }
321
322 if (r == 0x11) {
323 xlog("\t%s: Extend access because already in the list!\n", ip);
324 my_ips[pos].expire = now.tv_sec + grant_time;
325 return NF_ACCEPT;
326 }
327
328 xlog("\t%s: invalid command\n", ip);
329 return NF_DROP;
265 330 } }
266 331
267 inet_ntop(af, src, ip, sizeof(ip));
268 printf("DBEUG: ip=%s\n", ip);
332 r = brute_check(src, src_len, now.tv_sec);
333 if (r == -1) {
334 //xlog("\t%s: User tried too early! Brute force attack?\n", ip);
335 return NF_DROP;
336 }
337
338 //xlog("\t%s: ip is NOT in the white list.\n", ip);
269 339 r = test_2fa(data, data_len, now.tv_sec, ip); r = test_2fa(data, data_len, now.tv_sec, ip);
270 if (r == 1) {
271 add_ip(pos, src, src_len, &now);
272 verdict = NF_ACCEPT;
340 if (r == 0x11) {
341 add_ip(pos, src, src_len, now.tv_sec);
342 return NF_ACCEPT;
273 343 } }
274 344
275 printf("\tverdict=%s\n", verdict == NF_ACCEPT ? "ACCEPT" : "DROP");
276 return verdict;
345 xlog("\t%s: DROP.\n", ip);
346 return NF_DROP;
277 347 } }
278 348
279 349 /* /*
 
... ... static int queue_cb(const struct nlmsghdr *nlh, void *data)
287 357 struct nfgenmsg *nfg; struct nfgenmsg *nfg;
288 358 uint16_t plen; uint16_t plen;
289 359 unsigned char *payload; unsigned char *payload;
360 int ret;
290 361
291 362 if (nfq_nlmsg_parse(nlh, attr) < 0) { if (nfq_nlmsg_parse(nlh, attr) < 0) {
292 perror("problems parsing");
363 xlog("Problems parsing netlink message!\n");
293 364 return MNL_CB_ERROR; return MNL_CB_ERROR;
294 365 } }
295 366
296 367 nfg = mnl_nlmsg_get_payload(nlh); nfg = mnl_nlmsg_get_payload(nlh);
297 368
298 369 if (attr[NFQA_PACKET_HDR] == NULL) { if (attr[NFQA_PACKET_HDR] == NULL) {
299 fputs("metaheader not set\n", stderr);
370 xlog("Packet metaheader not set!\n");
300 371 return MNL_CB_ERROR; return MNL_CB_ERROR;
301 372 } }
302 373
 
... ... static int queue_cb(const struct nlmsghdr *nlh, void *data)
305 376
306 377 ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]); ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]);
307 378 id = ntohl(ph->packet_id); id = ntohl(ph->packet_id);
308 printf("packet received (id=%u hw=0x%04hx hook=%hhu, payload len %u"
379 xlog("packet received (id=%u hw=0x%04hx hook=%hhu, payload len %u"
309 380 " data=%p\n", " data=%p\n",
310 381 id, ntohs(ph->hw_protocol), ph->hook, plen, data); id, ntohs(ph->hw_protocol), ph->hook, plen, data);
311 382
312 383 verdict = process(ntohs(ph->hw_protocol), payload, plen); verdict = process(ntohs(ph->hw_protocol), payload, plen);
313 send_verdict(ntohs(nfg->res_id), id, verdict);
384 ret = send_verdict(ntohs(nfg->res_id), id, verdict);
385 if (ret == -1)
386 return MNL_CB_ERROR;
314 387
315 388 return MNL_CB_OK; return MNL_CB_OK;
316 389 } }
 
... ... static int queue_cb(const struct nlmsghdr *nlh, void *data)
318 391 /* /*
319 392 * Add a key to a struct user, ordering them correctly * Add a key to a struct user, ordering them correctly
320 393 */ */
321 void key_add(struct user *u, struct key *k)
394 static void key_add(struct user *u, struct key *k)
322 395 { {
323 396 struct key *q, *prev; struct key *q, *prev;
324 397
325 398 prev = NULL; prev = NULL;
326 399 q = u->head; q = u->head;
327 400 while (q) { while (q) {
328 printf("DEBUG: comparing q->id (%hhu) with k->id (%hhu)\n",
329 q->id, k->id);
330 401 if (q->id > k->id) if (q->id > k->id)
331 402 break; break;
332 403
 
... ... void key_add(struct user *u, struct key *k)
346 417 /* /*
347 418 * Returns a struct user by uid * Returns a struct user by uid
348 419 */ */
349 struct user *uid_to_user(const unsigned int uid)
420 static struct user *uid_to_user(const unsigned int uid)
350 421 { {
351 422 struct user *q; struct user *q;
352 423
 
... ... struct user *uid_to_user(const unsigned int uid)
365 436 * Returns the next free key slot. * Returns the next free key slot.
366 437 * Returns 0xFF if not available * Returns 0xFF if not available
367 438 */ */
368 unsigned char key_next_free(struct user *u)
439 static unsigned char key_next_free(struct user *u)
369 440 { {
370 441 struct key *k; struct key *k;
371 442 unsigned char min = 0; unsigned char min = 0;
 
... ... unsigned char key_next_free(struct user *u)
385 456 /* /*
386 457 * Process a client command * Process a client command
387 458 * Returns the number of bytes stored in @buf * Returns the number of bytes stored in @buf
459 * TODO: do we really heave at least 1 byte?
388 460 */ */
389 int process_client(const unsigned int uid, unsigned char *buf,
390 const unsigned int len)
461 static int process_client(const unsigned int uid, unsigned char *buf,
462 unsigned int n)
391 463 { {
392 464 unsigned char cmd; unsigned char cmd;
393 465 unsigned short i = 0; unsigned short i = 0;
394 466 int r; int r;
395 467
396 468 i = 0; i = 0;
397 cmd = buf[i++];
469 cmd = buf[i++]; n--;
398 470
399 if (cmd == NF2FA_CMD_ENROLL) {
471 while (cmd == NF2FA_CMD_ENROLL) {
400 472 struct user *u; struct user *u;
401 473 struct key k, *k2; struct key k, *k2;
402 unsigned char len8;
474 unsigned char len, len2;
403 475 struct timeval now; struct timeval now;
404 476
477 if (n < 1)
478 break;
479
405 480 memset(&k, 0, sizeof(struct key)); memset(&k, 0, sizeof(struct key));
406 481
407 len8 = buf[i++];
408 if (len8 > sizeof(k.name) - 1)
409 len8 = sizeof(k.name) - 1;
410 memcpy(k.name, buf + i, len8); i += len8;
411 k.name[len8] = '\0';
412 printf("DEBUG: ENROLL name=[%s]\n", k.name);
482 len = buf[i++]; n--;
483 if (len > n)
484 break;
485 if (len > sizeof(k.name) - 1)
486 len2 = sizeof(k.name) - 1;
487 else
488 len2 = len;
489 memcpy(k.name, buf + i, len2);
490 k.name[len2] = '\0';
491 i += len; n -= len;
492 //xlog("DEBUG: ENROLL name=[%s]\n", k.name);
413 493
414 494 i = 1; /* we now overwrite the buffer */ i = 1; /* we now overwrite the buffer */
415 495
 
... ... int process_client(const unsigned int uid, unsigned char *buf,
424 504
425 505 r = totp_base64_generate(k.key, KEY_DIGITS); r = totp_base64_generate(k.key, KEY_DIGITS);
426 506 if (r != 0) if (r != 0)
427 return i + protocol_enqueue_error(buf + i,
428 "cannot generate key: too low entropy");
507 return i + protocol_enqueue_error(buf + i, totp_error());
429 508
430 509 gettimeofday(&now, NULL); gettimeofday(&now, NULL);
431 510 k.itime = now.tv_sec; k.itime = now.tv_sec;
432 511
433 512 r = key_save(uid, &k); r = key_save(uid, &k);
434 513 if (r != 0) if (r != 0)
435 return i + protocol_enqueue_error(buf + i,
436 "cannot save key");
514 return i + protocol_enqueue_error(buf + i, key_error());
437 515
438 516 // Add the key to memory // Add the key to memory
439 517 u = users_head; u = users_head;
 
... ... int process_client(const unsigned int uid, unsigned char *buf,
469 547 return i; return i;
470 548 } }
471 549
472 if (cmd == NF2FA_CMD_LIST) {
550 while (cmd == NF2FA_CMD_LIST) {
473 551 struct user *u; struct user *u;
474 552 struct key *k; struct key *k;
475 553
 
... ... int process_client(const unsigned int uid, unsigned char *buf,
493 571 i += protocol_enqueue_string(buf + i, k->name); i += protocol_enqueue_string(buf + i, k->name);
494 572 x = htonl(k->ts); x = htonl(k->ts);
495 573 memcpy(buf + i, &x, 4); i += 4; memcpy(buf + i, &x, 4); i += 4;
574 x = htonl(k->itime);
575 memcpy(buf + i, &x, 4); i += 4;
496 576 i += protocol_enqueue_string(buf + i, k->ip); i += protocol_enqueue_string(buf + i, k->ip);
497 577
498 578 k = k->next; k = k->next;
 
... ... int process_client(const unsigned int uid, unsigned char *buf,
501 581 return i; return i;
502 582 } }
503 583
504 if (cmd == NF2FA_CMD_UNENROLL) {
584 while (cmd == NF2FA_CMD_UNENROLL) {
505 585 struct user *u; struct user *u;
506 586 struct key *k, *kprev; struct key *k, *kprev;
507 587 int r; int r;
508 588 unsigned char id; unsigned char id;
509 589
510 id = buf[i++];
590 if (n < 1)
591 break;
592
593 id = buf[i++]; n--;
511 594
512 595 i = 1; /* we now overwrite the buffer */ i = 1; /* we now overwrite the buffer */
513 596
514 597 r = key_remove(uid, id); r = key_remove(uid, id);
515 598 if (r != 0) if (r != 0)
516 return i + protocol_enqueue_error(buf + i,
517 "cannot remove key");
599 return i + protocol_enqueue_error(buf + i, key_error());
518 600
519 601 // Remove it from memory // Remove it from memory
520 602 u = users_head; u = users_head;
 
... ... int process_client(const unsigned int uid, unsigned char *buf,
542 624 } }
543 625
544 626 buf[i++] = 0x00; /* marks the success */ buf[i++] = 0x00; /* marks the success */
627 xlog("Unenrolled key %03hhu for uid %u.\n", id, uid);
545 628 return i; return i;
546 629 } }
547 630
548 return i + protocol_enqueue_error(buf + i, "unknown command");
631 return i + protocol_enqueue_error(buf + i, "unknown or invalid command");
549 632 } }
550 633
551 634 /* /*
552 635 * Load the keys for a user * Load the keys for a user
553 636 */ */
554 int load_keys_uid(struct user *u, const unsigned int uid)
637 static int load_keys_uid(struct user *u, const unsigned int uid)
555 638 { {
556 639 int err; int err;
557 640
 
... ... int load_keys_uid(struct user *u, const unsigned int uid)
563 646 snprintf(path, sizeof(path), "%s/%u", KEY_DIR, uid); snprintf(path, sizeof(path), "%s/%u", KEY_DIR, uid);
564 647 d = opendir(path); d = opendir(path);
565 648 if (!d) { if (!d) {
566 printf("Cannot open dir %s: %s!\n",
649 xlog("Cannot open dir %s: %s!\n",
567 650 path, strerror(errno)); path, strerror(errno));
568 651 break; break;
569 652 } }
 
... ... int load_keys_uid(struct user *u, const unsigned int uid)
585 668 if (strlen(de->d_name) != 3) if (strlen(de->d_name) != 3)
586 669 continue; continue;
587 670
588 //printf(" Loading key %s...\n", de->d_name);
671 //xlog(" Loading key %s...\n", de->d_name);
589 672 k = malloc(sizeof(struct key)); k = malloc(sizeof(struct key));
590 673 if (!k) { if (!k) {
591 printf("Cannot alloc memory!\n");
674 xlog("Cannot alloc memory!\n");
592 675 break; break;
593 676 } }
594 677
 
... ... int load_keys_uid(struct user *u, const unsigned int uid)
611 694 /* /*
612 695 * Load all keys from KEY_DIR * Load all keys from KEY_DIR
613 696 */ */
614 int load_keys(void)
697 static int load_keys(void)
615 698 { {
616 699 DIR *d; DIR *d;
617 700 int err, r; int err, r;
618 701
619 702 d = opendir(KEY_DIR); d = opendir(KEY_DIR);
620 703 if (!d) { if (!d) {
621 printf("Cannot open keys dir: %s!\n", strerror(errno));
704 xlog("Cannot open keys dir: %s!\n", strerror(errno));
622 705 return -1; return -1;
623 706 } }
624 707
 
... ... int load_keys(void)
639 722 if (de->d_name[0] == '.') if (de->d_name[0] == '.')
640 723 continue; continue;
641 724
642 //printf("Loading uid [%s]...\n", de->d_name);
725 //xlog("Loading uid [%s]...\n", de->d_name);
643 726
644 727 u = malloc(sizeof(struct user)); u = malloc(sizeof(struct user));
645 728 if (!u) { if (!u) {
646 printf("Cannot alloc memory!\n");
729 xlog("Cannot alloc memory!\n");
647 730 break; break;
648 731 } }
649 732 memset(u, 0, sizeof(struct user)); memset(u, 0, sizeof(struct user));
 
... ... int load_keys(void)
664 747 return err; return err;
665 748 } }
666 749
750 /*
751 * Drop privileges
752 * returns -1 on error
753 */
754 static int drop_privileges(void)
755 {
756 int ret, err;
757 cap_t caps;
758 cap_value_t cap_list[1];
759
760 // Be sure the rights are ok
761 chmod(KEY_DIR, 0700);
762
763 chdir("/");
764
765 err = -1;
766 while (1) {
767 caps = cap_get_proc();
768 if (!caps) {
769 xlog("Cannot obtain caps: %s!\n", strerror(errno));
770 break;
771 }
772
773 ret = cap_clear(caps);
774 if (ret == -1) {
775 xlog("Cannot clear caps: %s!\n", strerror(errno));
776 break;
777 }
778
779 cap_list[0] = CAP_NET_ADMIN;
780
781 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET);
782 if (ret == -1) {
783 xlog("Cannot set eff flags: %s!\n", strerror(errno));
784 break;
785 }
786
787 ret = cap_set_flag(caps, CAP_PERMITTED, 1, cap_list, CAP_SET);
788 if (ret == -1) {
789 xlog("Cannot set perm flags: %s!\n", strerror(errno));
790 break;
791 }
792
793 ret = cap_set_proc(caps);
794 if (ret == -1) {
795 xlog("Cannot set caps: %s!\n", strerror(errno));
796 break;
797 }
798
799 err = 0;
800 break;
801 }
802 if (caps)
803 cap_free(caps);
804
805 return err;
806 }
807
667 808 int main(int argc, char *argv[]) int main(int argc, char *argv[])
668 809 { {
669 810 unsigned char buf[MNL_SOCKET_BUFFER_SIZE]; unsigned char buf[MNL_SOCKET_BUFFER_SIZE];
670 811 struct nlmsghdr *nlh; struct nlmsghdr *nlh;
671 812 int ret, efd, fd1, fd2; int ret, efd, fd1, fd2;
672 unsigned int portid, queue_num;
813 unsigned int portid;
673 814 unsigned int i; unsigned int i;
674 815 struct epoll_event ev; struct epoll_event ev;
675 816 struct sockaddr_un sa_un; struct sockaddr_un sa_un;
676 817 socklen_t slen; socklen_t slen;
818 char *conf_file;
677 819
678 ret = load_keys();
820 xlog("Version: %s\n", NF2FA_VERSION);
821
822 if (argc >= 2)
823 conf_file = argv[1];
824 else
825 conf_file = CONF_FILE;
826 xlog("conf_file: %s\n", conf_file);
827
828 ret = conf_load(conf_file);
829 if (ret == -1)
830 return 1;
831
832 ret = drop_privileges();
833 if (ret != 0)
834 return 1;
835
836 ret = brute_init(bad_entries);
679 837 if (ret == -1) { if (ret == -1) {
680 printf("Cannot load keys!\n");
838 xerr("cannot init brute module: %s", brute_error());
681 839 return 1; return 1;
682 840 } }
683 841
684 if (argc < 2)
685 queue_num = 0x4545;
686 else
687 queue_num = strtoul(argv[1], NULL, 0);
688 printf("queue_num: %u\n", queue_num);
842 ret = load_keys();
843 if (ret == -1)
844 return 1;
845
689 846
690 847 nl = mnl_socket_open(NETLINK_NETFILTER); nl = mnl_socket_open(NETLINK_NETFILTER);
691 848 if (nl == NULL) { if (nl == NULL) {
 
... ... int main(int argc, char *argv[])
697 854 perror("mnl_socket_bind"); perror("mnl_socket_bind");
698 855 return 1; return 1;
699 856 } }
700 portid = mnl_socket_get_portid(nl);
701 857
702 nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, 0);
703 nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_PF_UNBIND);
704 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
705 perror("mnl_socket_send");
858 unlink(sock_path);
859 fd2 = socket(AF_UNIX, SOCK_STREAM, 0);
860 if (fd2 == -1) {
861 xlog("Cannot create unix socket: %s!\n", strerror(errno));
706 862 return 1; return 1;
707 863 } }
708 864
709 nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, 0);
710 nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_PF_BIND);
711 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
712 perror("mnl_socket_send");
865 memset(&sa_un, 0, sizeof(struct sockaddr_un));
866 sa_un.sun_family = AF_UNIX;
867 strncpy(sa_un.sun_path, sock_path, sizeof(sa_un.sun_path) - 1);
868 slen = sizeof(struct sockaddr_un);
869 ret = bind(fd2, (struct sockaddr *) &sa_un, slen);
870 if (ret == -1) {
871 xlog("Cannot bind unix socket: %s!\n", strerror(errno));
713 872 return 1; return 1;
714 873 } }
874 chmod(sock_path, 0666);
875
715 876
716 nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue_num);
877 portid = mnl_socket_get_portid(nl);
878
879 nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue);
717 880 nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND); nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND);
718 881 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
719 perror("mnl_socket_send");
882 perror("mnl_socket_send cmd_bind");
720 883 return 1; return 1;
721 884 } }
722 885
723 nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue_num);
886 nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue);
724 887 nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff); nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff);
725 888 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
726 perror("mnl_socket_send");
889 perror("mnl_socket_send copy_packet");
727 890 return 1; return 1;
728 891 } }
729 892
 
... ... int main(int argc, char *argv[])
733 896 ret = 1; ret = 1;
734 897 mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &ret, sizeof(int)); mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &ret, sizeof(int));
735 898
899
736 900 efd = epoll_create1(0); efd = epoll_create1(0);
737 901 if (efd == -1) { if (efd == -1) {
738 printf("Cannot create epoll socket: %s!\n", strerror(errno));
902 xlog("Cannot create epoll socket: %s!\n", strerror(errno));
739 903 return 1; return 1;
740 904 } }
741 905
742 906 fd1 = mnl_socket_get_fd(nl); fd1 = mnl_socket_get_fd(nl);
743 printf("fd1=%d\n", fd1);
744 907 memset(&ev, 0, sizeof(struct epoll_event)); memset(&ev, 0, sizeof(struct epoll_event));
745 908 ev.events = EPOLLIN; ev.events = EPOLLIN;
746 909 ev.data.fd = fd1; ev.data.fd = fd1;
747 910 if (epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &ev) == -1) { if (epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &ev) == -1) {
748 printf("Cannot add nl socket to epoll: %s!\n",
911 xlog("Cannot add nl socket to epoll: %s!\n",
749 912 strerror(errno)); strerror(errno));
750 913 return 1; return 1;
751 914 } }
752 915
753 unlink(SOCKET_NAME);
754 fd2 = socket(AF_UNIX, SOCK_STREAM, 0);
755 if (fd2 == -1) {
756 printf("Cannot create unix socket: %s!\n", strerror(errno));
757 return 1;
758 }
759 memset(&sa_un, 0, sizeof(struct sockaddr_un));
760 sa_un.sun_family = AF_UNIX;
761 strncpy(sa_un.sun_path, SOCKET_NAME, sizeof(sa_un.sun_path) - 1);
762 slen = sizeof(struct sockaddr_un);
763 ret = bind(fd2, (struct sockaddr *) &sa_un, slen);
764 if (ret == -1) {
765 printf("Cannot bind unix socket: %s!\n", strerror(errno));
766 return 1;
767 }
916 // Preparing unix socket for control
768 917 listen(fd2, 16); listen(fd2, 16);
769 chmod(SOCKET_NAME, 0666);
770 printf("fd2=%d\n", fd2);
771 918 memset(&ev, 0, sizeof(struct epoll_event)); memset(&ev, 0, sizeof(struct epoll_event));
772 919 ev.events = EPOLLIN; ev.events = EPOLLIN;
773 920 ev.data.fd = fd2; ev.data.fd = fd2;
774 921 if (epoll_ctl(efd, EPOLL_CTL_ADD, fd2, &ev) == -1) { if (epoll_ctl(efd, EPOLL_CTL_ADD, fd2, &ev) == -1) {
775 printf("Cannot add unix socket to epoll: %s!\n",
922 xlog("Cannot add unix socket to epoll: %s!\n",
776 923 strerror(errno)); strerror(errno));
777 924 return 1; return 1;
778 925 } }
 
... ... int main(int argc, char *argv[])
784 931 for (;;) { for (;;) {
785 932 ret = epoll_wait(efd, &ev, 1, -1); ret = epoll_wait(efd, &ev, 1, -1);
786 933 if (ret == -1) { if (ret == -1) {
787 printf("Cannot wait for epoll: %s!\n",
934 xlog("Cannot wait for epoll: %s!\n",
788 935 strerror(errno)); strerror(errno));
789 936 return 1; return 1;
790 937 } }
 
... ... int main(int argc, char *argv[])
812 959
813 960 csock = accept(fd2, NULL, NULL); csock = accept(fd2, NULL, NULL);
814 961 if (csock == -1) { if (csock == -1) {
815 printf("Cannot accept: %s!\n", strerror(errno));
962 xlog("Cannot accept: %s!\n", strerror(errno));
816 963 continue; continue;
817 964 } }
818 965
819 966 slen = sizeof(struct ucred); slen = sizeof(struct ucred);
820 967 if (getsockopt(csock, SOL_SOCKET, SO_PEERCRED, if (getsockopt(csock, SOL_SOCKET, SO_PEERCRED,
821 968 &ucred, &slen) == -1) { &ucred, &slen) == -1) {
822 printf("Canno find out uid/gid of peer: %s!\n",
969 xlog("Cannot find out uid/gid of peer: %s!\n",
823 970 strerror(errno)); strerror(errno));
824 971 goto clean; goto clean;
825 972 } }
826 printf("Credentials from SO_PEERCRED: pid=%ld, euid=%ld, egid=%ld\n",
827 (long) ucred.pid, (long) ucred.uid, (long) ucred.gid);
973 xlog("Connection from "
974 " pid=%ld, euid=%ld, egid=%ld\n",
975 (long) ucred.pid, (long) ucred.uid,
976 (long) ucred.gid);
828 977
829 978 // Set timeout // Set timeout
830 979 tv.tv_sec = 0; tv.tv_usec = 20000; tv.tv_sec = 0; tv.tv_usec = 20000;
 
... ... int main(int argc, char *argv[])
833 982
834 983 n = recv(csock, buf, sizeof(buf), 0); n = recv(csock, buf, sizeof(buf), 0);
835 984 if (n == -1) { if (n == -1) {
836 printf("Cannot receive: %s\n", strerror(errno));
985 xlog("Cannot receive: %s\n", strerror(errno));
837 986 goto clean; goto clean;
838 987 } }
839 printf("Data on UNIX socket:\n"); dump(buf, n);
988 //xlog("Data on UNIX socket:\n"); dump(buf, n);
840 989
841 990 n = process_client(ucred.uid, buf, n); n = process_client(ucred.uid, buf, n);
842 991 if (n == -1) if (n == -1)
 
... ... int main(int argc, char *argv[])
844 993
845 994 n = send(csock, buf, n, 0); n = send(csock, buf, n, 0);
846 995 if (n == -1) if (n == -1)
847 printf("Cannot send: %s!\n", strerror(errno));
996 xlog("Cannot send: %s!\n", strerror(errno));
848 997
849 998 clean: clean:
850 999 close(csock); close(csock);
File nf2fad.val added (mode: 100755) (index 0000000..c6222cb)
1 #!/bin/bash
2
3 valgrind --leak-check=full --track-origins=yes \
4 ./nf2fad "${@}"
5
File protocol.c changed (mode: 100644) (index 48a03b0..dd64b52)
1 1 #define _GNU_SOURCE #define _GNU_SOURCE
2 2
3 #include <stdio.h>
4 3 #include <string.h> #include <string.h>
5 4
6 5 #include "protocol.h" #include "protocol.h"
 
... ... unsigned short protocol_enqueue_string(unsigned char *buf, const char *s)
12 11 { {
13 12 unsigned short i = 0, len; unsigned short i = 0, len;
14 13
15 printf("DEBUG: enqueue string [%s]\n", s);
16
17 14 buf[i++] = len = strlen(s); buf[i++] = len = strlen(s);
18 15 memcpy(buf + i, s, len); i += len; memcpy(buf + i, s, len); i += len;
19 16
File totp.c changed (mode: 100644) (index 9062a69..a3f5324)
1 1 #include "totp.h" #include "totp.h"
2 2
3 3 #include <stdlib.h> #include <stdlib.h>
4 #include <stdio.h>
4 5 #include <openssl/hmac.h> #include <openssl/hmac.h>
5 6 #include <openssl/evp.h> #include <openssl/evp.h>
6 7 #include <ctype.h> #include <ctype.h>
 
12 13 #include <qrencode.h> #include <qrencode.h>
13 14
14 15 static char *totp_base32_tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; static char *totp_base32_tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
16 static char error[256];
17
18 char *totp_error(void)
19 {
20 return error;
21 }
15 22
16 23 /* /*
17 24 * Generate a secret * Generate a secret
 
... ... static char *totp_base32_tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
20 27 int totp_base64_generate(char *out, const unsigned char digits) int totp_base64_generate(char *out, const unsigned char digits)
21 28 { {
22 29 unsigned char i, ra[256]; unsigned char i, ra[256];
23 int r;
30 ssize_t r;
24 31
25 32 do { do {
26 33 r = getrandom(ra, digits, 0); r = getrandom(ra, digits, 0);
27 34 } while ((r == -1) && (errno == EAGAIN)); } while ((r == -1) && (errno == EAGAIN));
28 if (r == -1)
35 if (r == -1) {
36 snprintf(error, sizeof(error), "cannot get enough random bytes");
29 37 return -1; return -1;
38 }
30 39
31 40 for (i = 0; i < digits; i++) for (i = 0; i < digits; i++)
32 41 out[i] = totp_base32_tab[ra[i] % 32]; out[i] = totp_base32_tab[ra[i] % 32];
 
... ... int totp_base64_generate(char *out, const unsigned char digits)
41 50 unsigned char totp_char_to_index(const char c) unsigned char totp_char_to_index(const char c)
42 51 { {
43 52 const char *x; const char *x;
44 char q;
53 int q;
45 54
46 55 q = toupper(c); q = toupper(c);
47 56 x = strchr(totp_base32_tab, q); x = strchr(totp_base32_tab, q);
 
... ... int totp_base32_decode(unsigned char *out, const unsigned char out_size,
86 95 out[i++] = buf >> buf_bits; out[i++] = buf >> buf_bits;
87 96 buf &= ((1 << buf_bits) - 1); buf &= ((1 << buf_bits) - 1);
88 97
89 if (i == out_size)
98 if (i == out_size) {
99 snprintf(error, sizeof(error), "buffer too small");
90 100 return -1; return -1;
101 }
91 102 } }
92 103
93 104 return i; return i;
 
... ... int totp_base32_decode(unsigned char *out, const unsigned char out_size,
96 107 /* /*
97 108 * Converts a two digit hex string into a unsigned char * Converts a two digit hex string into a unsigned char
98 109 */ */
99 unsigned char totp_hex2bin(const char *s)
110 static unsigned char totp_hex2bin(const char *s)
100 111 { {
101 112 unsigned char i, v[2]; unsigned char i, v[2];
102 113
103 114 for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
104 char c;
115 int c;
105 116
106 117 c = toupper(s[i]); c = toupper(s[i]);
107 118 if ((c >= '0') && (c <= '9')) if ((c >= '0') && (c <= '9'))
 
... ... int totp_compute(char *out, const char *key, unsigned int tc,
129 140 unsigned int v; unsigned int v;
130 141 unsigned long long z; unsigned long long z;
131 142
132 printf("DEBUG: %s: key=%s tc=%u\n", __func__, key, tc);
143 //printf("DEBUG: %s: key=%s tc=%u\n", __func__, key, tc);
133 144
134 145 r = totp_base32_decode(key_bin, sizeof(key_bin), key); r = totp_base32_decode(key_bin, sizeof(key_bin), key);
135 146 if (r == -1) if (r == -1)
136 147 return -1; return -1;
137 148 key_len = r; key_len = r;
138 dump(key_bin, key_len);
139 149
140 150 snprintf(stc, sizeof(stc), "%016x", tc); snprintf(stc, sizeof(stc), "%016x", tc);
141 151 // Transform stc into a binary // Transform stc into a binary
 
... ... int totp_verify_tc(const char *key, const unsigned int tc, const char *pin)
174 184 if (r == -1) if (r == -1)
175 185 return -1; return -1;
176 186
177 printf("DEBUG: tc=%u Comparing %s with %s\n", tc, cpin, pin);
178 187 if (strcmp(cpin, pin) != 0) if (strcmp(cpin, pin) != 0)
179 188 return 0; return 0;
180 189
 
... ... static void encode(char *out, const char *in)
245 254 /* /*
246 255 * Generates a UTF-8 QR code * Generates a UTF-8 QR code
247 256 */ */
248 void totp_text(const char *secret, const char *name)
257 int totp_text(const char *secret, const char *name)
249 258 { {
250 259 char host[128], extra[256]; char host[128], extra[256];
251 260 QRcode *qr; QRcode *qr;
 
... ... void totp_text(const char *secret, const char *name)
261 270 encode(ename, name); encode(ename, name);
262 271 snprintf(extra, sizeof(extra), "otpauth://totp/%s?secret=%s&issuer=%s", snprintf(extra, sizeof(extra), "otpauth://totp/%s?secret=%s&issuer=%s",
263 272 ename, secret, ehost); ename, secret, ehost);
264 printf("DEBUG: extra=%s\n", extra);
265 273
266 274 qr = QRcode_encodeString(extra, 0, QR_ECLEVEL_M, QR_MODE_8, 1); qr = QRcode_encodeString(extra, 0, QR_ECLEVEL_M, QR_MODE_8, 1);
267 275 if (!qr) { if (!qr) {
268 printf("Cannot generate qr code: %s\n", strerror(errno));
269 exit(1);
276 snprintf(error, sizeof(error),
277 "cannot generate qr code: %s", strerror(errno));
278 return -1;
270 279 } }
271 280
272 281 // top margin // top margin
 
... ... void totp_text(const char *secret, const char *name)
296 305 printf("\n"); printf("\n");
297 306
298 307 QRcode_free(qr); QRcode_free(qr);
308
309 return 0;
299 310 } }
300 311
File totp.h changed (mode: 100644) (index de72caf..d777066)
1 char *totp_error(void);
1 2 int totp_base64_generate(char *out, const unsigned char digits); int totp_base64_generate(char *out, const unsigned char digits);
2 3 unsigned char totp_char_to_index(const char c); unsigned char totp_char_to_index(const char c);
3 4 int totp_base32_decode(unsigned char *out, int totp_base32_decode(unsigned char *out,
 
... ... int totp_verify_tc(const char *key, const unsigned int tc,
8 9 const char *pin); const char *pin);
9 10 int totp_verify(const char *key, const unsigned int tc, int totp_verify(const char *key, const unsigned int tc,
10 11 const unsigned int last_used, const char *pin); const unsigned int last_used, const char *pin);
11 void totp_text(const char *secret, const char *name);
12 int totp_text(const char *secret, const char *name);
12 13
File util.c changed (mode: 100644) (index eb3fdf9..462577c)
1 1 #define _GNU_SOURCE #define _GNU_SOURCE
2 2
3 3 #include <stdio.h> #include <stdio.h>
4 #include <stdarg.h>
4 5
5 6 #include "util.h" #include "util.h"
6 7
8 /*
9 * Logging function
10 */
11 void xlog(const char *format, ...)
12 {
13 va_list ap;
14 char line[512];
15
16 va_start(ap, format);
17 vsnprintf(line, sizeof(line), format, ap);
18 va_end(ap);
19
20 printf("%s", line);
21 }
22
23 /*
24 * Logging function
25 */
26 void xerr(const char *format, ...)
27 {
28 va_list ap;
29 char line[512];
30
31 va_start(ap, format);
32 vsnprintf(line, sizeof(line), format, ap);
33 va_end(ap);
34
35 fprintf(stderr, "%s", line);
36 }
37
7 38 void dump(const unsigned char *d, const unsigned int len) void dump(const unsigned char *d, const unsigned int len)
8 39 { {
9 40 unsigned int i; unsigned int i;
10 41
11 printf("Dump:\n");
42 xlog("Dump:");
12 43 for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
13 44 if (i % 16 == 0) if (i % 16 == 0)
14 printf("\t");
15 printf(" %02hhx", d[i]);
45 xlog("\t");
46 xlog(" %02hhx", d[i]);
16 47 if (i % 16 == 15) if (i % 16 == 15)
17 printf("\n");
48 xlog("\n");
18 49 } }
19 printf("\n");
50 xlog("\n");
20 51 } }
52
File util.h changed (mode: 100644) (index 06a36fc..a6a603f)
1 void xlog(const char *format, ...);
2 void xerr(const char *format, ...);
1 3 void dump(const unsigned char *d, const unsigned int len); void dump(const unsigned char *d, const unsigned int len);
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/catalinux/nf2fa

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/catalinux/nf2fa

Clone this repository using git:
git clone git://git.rocketgit.com/user/catalinux/nf2fa

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main