/nf2fac.c (2e31ed9addec259fb535ad35e664111e1ef9610a) (5956 bytes) (mode 100644) (type blob)

/*
 * Client for nf2fa daemon
 * Author: Catalin(ux) M. BOIE
 */

#define _GNU_SOURCE

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>

#include "nf2fa_common.h"
#include "util.h"
#include "conf.h"
#include "totp.h"
#include "key.h"
#include "protocol.h"

static void help(void)
{
	fprintf(stderr, "Usage: nf2afc <command> [options]\n");
	fprintf(stderr, "Commands:\n");
	fprintf(stderr, "\tenroll <name> - enroll new device(s)\n");
	fprintf(stderr, "\tlist - list the enrollments\n");
	fprintf(stderr, "\tunenroll <id> - unenroll a device\n");
}

int main(int argc, char *argv[])
{
	unsigned char buf[8 * 4096];
	int sock, r;
	struct sockaddr_un sa_un;
	socklen_t slen;
	ssize_t n;
	unsigned short i;
	unsigned char cmd, err;
	struct key k;

	if (argc < 2) {
		help();
		return 1;
	}

	r = conf_load(CONF_FILE);
	if (r == -1) {
		fprintf(stderr, "Cannot load conf file!\n");
		return 1;
	}

	i = 0;
	if (strcmp(argv[1], "enroll") == 0) {
		if (argc < 3) {
			help();
			return 1;
		}

		snprintf(k.name, sizeof(k.name), "%s", argv[2]);

		while (1) {
			char pass2[15];

			r = read_password("Password (only 0-9 and a-f): ",
				k.pass, sizeof(k.pass));
			if (r == -1)
				return 1;

			r = read_password("Password (confirmation): ",
				pass2, sizeof(pass2));
			if (r == -1)
				return 1;

			r = key_pass_validate(k.pass, pass2);
			if (r == -1) {
				fprintf(stderr, "Error: %s\n", key_error());
				continue;
			}

			break;
		}

		buf[i++] = NF2FA_CMD_ENROLL;
		i += protocol_enqueue_string(buf + i, k.name);
		i += protocol_enqueue_string(buf + i, k.pass);
	} else if (strcmp(argv[1], "list") == 0) {
		buf[i++] = NF2FA_CMD_LIST;
	} else if (strcmp(argv[1], "unenroll") == 0) {
		unsigned char id;
		char sid[4];

		if (argc < 3) {
			help();
			return 1;
		}

		id = strtoul(argv[2], NULL, 10);
		sprintf(sid, "%03hhu", id);
		if (strcmp(sid, argv[2]) != 0) {
			fprintf(stderr,
				"Error: Invalid id! Must be XXX (0 <= X <= 9)\n");
			return 1;
		}
		buf[i++] = NF2FA_CMD_UNENROLL;
		buf[i++] = id;
	} else {
		fprintf(stderr, "Error: unknown command!\n");
		help();
		return 1;
	}

	sock = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sock == -1) {
		fprintf(stderr, "Error: cannot create unix socket: %s!\n",
			strerror(errno));
		return 1;
	}
	memset(&sa_un, 0, sizeof(struct sockaddr_un));
	sa_un.sun_family = AF_UNIX;
	strncpy(sa_un.sun_path, cfg_sock_path, sizeof(sa_un.sun_path) - 1);
	slen = sizeof(struct sockaddr_un);

	n = connect(sock, (struct sockaddr *) &sa_un, slen);
	if (n == -1) {
		fprintf(stderr, "Error: cannot connect to nf2fa daemon: %s!\n",
			strerror(errno));
		return 1;
	}

	n = send(sock, buf, i, 0);
	if (n == -1) {
		fprintf(stderr, "Error: cannot send data to nf2fa daemon: %s!\n",
			strerror(errno));
		return 1;
	}

	n = recv(sock, buf, sizeof(buf), 0);
	if (n == -1) {
		fprintf(stderr, "Error: cannot receive data from nf2fa daemon: %s!\n",
			strerror(errno));
		return 1;
	}
	if (n == 0) {
		fprintf(stderr,
			"Error: nf2fa daemon unexpectedly closed the connection.\n");
		return 1;
	}
	if (n < 2) {
		fprintf(stderr, "Error: nf2fa daemon sent partial data.\n");
		return 1;
	}

	close(sock);

	//printf("DEBUG: Received:\n");
	//dump(buf, n);

	i = 0;
	cmd = buf[i++]; n--;
	err = buf[i++]; n--;

	while (err != 0x00) {
		char error[64];
		unsigned char len, len2;

		len = buf[i++]; n--;
		if (len > n)
			break;
		if (len > sizeof(error) - 1)
			len2 = sizeof(error) - 1;
		else
			len2 = len;
		memcpy(error, buf + i, len2);
		error[len2] = '\0';
		i += len; n -= len;

		fprintf(stderr, "Error: %s!\n", error);
		return 1;
	}

	while (cmd == NF2FA_CMD_ENROLL) {
		char info[128];
		unsigned char id, len, len2;
		int r;

		if (n < 2)
			break;

		id = buf[i++]; n--;
		len = buf[i++]; n--;
		if (len > n)
			break;
		if (len > sizeof(k.key) - 1)
			len2 = sizeof(k.key) - 1;
		else
			len2 = len;
		memcpy(k.key, buf + i, len2);
		k.key[len2] = '\0';
		i += len; n -= len;

		printf("Key is %s (id %03hhu)."
			" Scan the QR code below or type the key.\n",
			k.key, id);
		snprintf(info, sizeof(info), "%s - id %03hhu", k.name, id);
		r = totp_text(k.key, info);
		if (r != 0) {
			fprintf(stderr, "Error: %s\n", totp_error());
			return 1;
		}
		return 0;
	}

	while (cmd == NF2FA_CMD_LIST) {
		int err = 1;

		if (n == 0) {
			printf("No enrollments.\n");
			return 0;
		}

		printf("No   Enroll time       Name\n");
		while (1) {
			struct key k;
			unsigned int x;
			char t[32], itime[32];
			struct tm tm;
			unsigned char len, len2;

			if (n == 0) {
				err = 0;
				break;
			}

			k.id = buf[i++]; n--;

			len = buf[i++]; n--;
			if (len > n)
				break;
			if (len > sizeof(k.name) - 1)
				len2 = sizeof(k.name) - 1;
			else
				len2 = len;
			memcpy(k.name, buf + i, len2);
			k.name[len2] = '\0';
			i += len; n -= len;

			if (n < 4)
				break;
			memcpy(&x, buf + i, 4);
			k.ts = ntohl(x);
			i += 4; n -= 4;

			if (n < 4)
				break;
			memcpy(&x, buf + i, 4); i += 4; n -= 4;
			k.itime = ntohl(x);

			if (n < 1)
				break;
			len = buf[i++]; n--;
			if (len > n)
				break;
			if (len > sizeof(k.ip) - 1)
				len2 = sizeof(k.ip) - 1;
			else
				len2 = len;
			memcpy(k.ip, buf + i, len2);
			k.ip[len2] = '\0';
			i += len; n -= len;

			// show
			if (k.ts == 0) {
				sprintf(t, "%-14s", "not used");
			} else {
				localtime_r(&k.ts, &tm);
				strftime(t, sizeof(t), "%F %H:%M", &tm);
			}
			localtime_r(&k.itime, &tm);
			strftime(itime, sizeof(itime), "%F %H:%M", &tm);
			printf("%03hhu  %s  %s\n", k.id, itime, k.name);
			if (k.ts)
				printf("     Last access from IP %s on %s\n",
					k.ip, t);
		}
		if (err)
			break;

		return 0;
	}

	while (cmd == NF2FA_CMD_UNENROLL) {
		printf("Successfully un-enrolled.\n");
		return 0;
	}

	fprintf(stderr, "Unknown or broken answer [0x%02hhx]!\n", buf[0]);
	return 1;
}


Mode Type Size Ref File
100644 blob 69 7fd8a9d0de665239e50a919a7d7d2fdfbf43ce63 .gitignore
100644 blob 35147 94a9ed024d3859793618152ea559a168bbcbb5e2 LICENSE
100644 blob 1412 a5cc3f042afaf23eef1e4f62ad389f8490a3c12d Makefile.in
100644 blob 7268 acff51935549658d20725127d46bf60937667eed README
100644 blob 1082 c06bbd6ae0b382ac7ed331b228a94f9d2a07e785 TODO
100644 blob 2026 9b8efef5bf03e9a091c1adcc5c5596358d2a8ef7 brute.c
100644 blob 164 6a8b864b63fbde74b11f2661cd9e66fa01fd4ef0 brute.h
100644 blob 2617 6e510eb0d62c3a1e8ad3de7bd67d0a3b0b161ffd conf.c
100644 blob 317 f77a18816e66b29a96f86dd5b5fe91cfa81bdd7c conf.h
100755 blob 30 92c4bc48245c00408cd7e1fd89bc1a03058f4ce4 configure
100755 blob 16967 e058c68e85b03661803926184406b16fe0b0e089 duilder
100644 blob 1303 c5e205558339078bcab3c159e221a4b0f786a782 duilder.conf
100644 blob 4636 02a69675e8817ab3a43ad699ab17516c64d53b86 key.c
100644 blob 591 556d51530751878ffd39befd1dad38432de305f8 key.h
100644 blob 1030 8a169dd5e42638b21cd9fd75ab7e08ab10c60adb nf2fa.conf.sample
100644 blob 154 5d0ed3968f0b17bb93ea1a18cc6b488bebc4ccf0 nf2fa.service
100644 blob 1205 b1efbabda76ff8f52c409d7af85e8477163c4b34 nf2fa.spec.in
100644 blob 114 be8b674b4e2ba49dc02b5c5ae22bf27bba1dfaae nf2fa_common.h.in
100644 blob 5956 2e31ed9addec259fb535ad35e664111e1ef9610a nf2fac.c
100644 blob 24042 1b93d54f37ca1ffc6ed4953b5970a7894405bff5 nf2fad.c
100755 blob 80 c6222cbb68fbb975695f75292800e88fd9d5fe48 nf2fad.val
100644 blob 821 7c8e1a5e7deea795a3262ea61d1aea15ffae91c6 protocol.c
100644 blob 169 bb0764761a7d1337d7a8ba304f982ecbac59786a protocol.h
100644 blob 6643 0179a5ee946e6d564410358921fee3cf3e6700bd totp.c
100644 blob 565 d77706654b34b74075971d57c061ab7299f2bdd4 totp.h
100644 blob 1900 2d337fa42d6e7623575de1f1e0830842b79cda6a util.c
100644 blob 279 fef1852dd2f2d786e3873dac657432f843d94924 util.h
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