/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 1315 fd1e2fa2d71ff0d6a995ca0ac9f3ef33f93c48f5 Makefile.in
100644 blob 7268 acff51935549658d20725127d46bf60937667eed README
100644 blob 1082 c06bbd6ae0b382ac7ed331b228a94f9d2a07e785 TODO
100644 blob 2050 7dd67889f7d232ab2b831074fd9df9cf883e075e 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 16777 bcef40a7460025b9206d17e35475424e72e2a230 duilder
100644 blob 1233 1824f10a82b3a08ea8bd335369b1733c3dd8588c 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 6340 e74860ef16585a27f601422ff6ba1b8468c0ae4c 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