Created
December 18, 2012 19:02
-
-
Save jpmens/4330892 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* sshpubkeys (C)2012 by Jan-Piet Mens | |
*/ | |
#define FUSE_USE_VERSION 25 | |
#include <fuse.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <ctype.h> | |
#include <stdlib.h> | |
#include <ldns/ldns.h> | |
#define DOMAINFILE "/domain" | |
char *domain; | |
/* FIXME: needs linked list */ | |
#define MAXSERVERS 10 | |
static char *servers[MAXSERVERS] = { | |
// "127.0.0.1" | |
"192.168.33.1" | |
}; | |
int nservers = 1; | |
ldns_resolver *new_resolver() | |
{ | |
ldns_resolver *res = NULL; | |
ldns_rdf *tmp; | |
int n; | |
res = ldns_resolver_new(); | |
for (n = 0; n < nservers; n++) { | |
printf("----resolver: add %s\n", servers[n]); | |
tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, servers[n]); | |
if (!tmp) { | |
tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, servers[n]); | |
} | |
if (!tmp) { | |
ldns_resolver_deep_free(res); | |
puts("failed to create resolver"); | |
continue; | |
} | |
ldns_resolver_push_nameserver(res, tmp); | |
ldns_rdf_deep_free(tmp); | |
} | |
return res; | |
} | |
int getSSHkeys(char *qname, char *target, long targetlen) | |
{ | |
ldns_resolver *res = NULL; | |
ldns_rdf *d = NULL; | |
ldns_pkt *p = NULL; | |
ldns_rr_list *txt = NULL; | |
char fqdn[BUFSIZ]; | |
sprintf(fqdn, "%s.%s", qname, domain); | |
printf("********* getSSHkeys(%s)\n", fqdn); | |
if ((d = ldns_dname_new_frm_str(fqdn)) == NULL) { | |
return (1); | |
} | |
if ((res = new_resolver()) == NULL) { | |
return (1); | |
} | |
/* use the resolver to send a query for the mx | |
* records of the domain given on the command line | |
*/ | |
p = ldns_resolver_query(res, | |
d, | |
LDNS_RR_TYPE_TXT, | |
LDNS_RR_CLASS_IN, | |
LDNS_RD); | |
ldns_rdf_deep_free(d); | |
if (!p) { | |
return (1); | |
} else { | |
/* retrieve the TXT records from the answer section of that | |
* packet | |
*/ | |
txt = ldns_pkt_rr_list_by_type(p, | |
LDNS_RR_TYPE_TXT, | |
LDNS_SECTION_ANSWER); | |
if (!txt) { | |
fprintf(stderr, "%s NXDOMAIN or NODATA\n", fqdn); | |
ldns_pkt_free(p); | |
ldns_resolver_deep_free(res); | |
return (1); | |
} else { | |
long n, i; | |
char *str, *bp, *tp = target; | |
ldns_rdf *t; | |
ldns_rr_list_sort(txt); | |
// ldns_rr_list_print(stdout, txt); | |
if ((n = ldns_rr_list_rr_count(txt)) < 1) { | |
printf("Expecting at least 1 answer: got %ld\n", n); | |
return (1); | |
} | |
for (i = 0; i < ldns_rr_list_rr_count(txt); i++) { | |
int j; | |
for (j = 0; j < ldns_rr_rd_count(ldns_rr_list_rr(txt,i)); j++) { | |
t = ldns_rr_rdf(ldns_rr_list_rr(txt, i), j); | |
if (!t) | |
continue; | |
str = ldns_rdf2str(t); | |
for (bp = str; bp && *bp; bp++) { | |
if (*bp != '"') | |
*tp++ = *bp; | |
} | |
free(str); | |
*tp = 0; | |
} | |
*tp++ = '\n'; | |
*tp = 0; | |
} | |
ldns_rr_list_deep_free(txt); | |
} | |
} | |
ldns_pkt_free(p); | |
ldns_resolver_deep_free(res); | |
return 0; | |
} | |
#define BLEN 10120 | |
/* ------------------------------------------------------------------------ */ | |
/* | |
* FIXME: getattr() reads the keys from DNS and read() does so too; should | |
* be a way to cache inbetween, but I'm not sure whether this code | |
* is threaded | |
*/ | |
static int sshpub_getattr(const char *path, struct stat *stbuf) | |
{ | |
int n; | |
char buf[BLEN]; | |
long targetlen = BLEN; | |
memset(stbuf, 0, sizeof(struct stat)); | |
printf("GETATTR [%s, %0X]\n", path, stbuf->st_mode); | |
time_t now = time(NULL); | |
stbuf->st_uid = geteuid(); | |
stbuf->st_gid = getegid(); | |
stbuf->st_ctime = now; | |
stbuf->st_mtime = now; | |
stbuf->st_atime = now; | |
if (strcmp(path, "/") == 0) { | |
stbuf->st_mode = S_IFDIR | 0755; | |
stbuf->st_nlink = 2; | |
return 0; | |
} else if (strcmp(path, DOMAINFILE) == 0) { | |
stbuf->st_mode = S_IFREG | 0444; | |
stbuf->st_nlink = 1; | |
stbuf->st_size = strlen(domain) + 1; | |
return 0; | |
} | |
for (n = 0; n < MAXSERVERS && servers[n]; n++) { | |
if (strcmp(path+1, servers[n]) == 0) { | |
stbuf->st_mode = S_IFDIR | 0755; | |
stbuf->st_nlink = 2; | |
stbuf->st_size = strlen(servers[n]); | |
return 0; | |
} | |
} | |
if (getSSHkeys((char *)path+1, buf, targetlen) == 0) { | |
stbuf->st_mode = S_IFREG | 0444; | |
stbuf->st_nlink = 1; | |
stbuf->st_size = strlen(buf); | |
return 0; | |
} | |
return -ENOENT; | |
} | |
static int sshpub_readdir(const char *path, void *buf, fuse_fill_dir_t filler, | |
off_t offset, struct fuse_file_info *fi) | |
{ | |
(void) offset; | |
(void) fi; | |
int n; | |
if(strcmp(path, "/") != 0) | |
return -ENOENT; | |
filler(buf, ".", NULL, 0); | |
filler(buf, "..", NULL, 0); | |
filler(buf, "domain", NULL, 0); | |
for (n = 0; n < MAXSERVERS && servers[n]; n++) { | |
char path[1024]; | |
sprintf(path, "/%s", servers[n]); | |
filler(buf, path + 1, NULL, 0); | |
} | |
return 0; | |
} | |
static int sshpub_open(const char *path, struct fuse_file_info *fi) | |
{ | |
/* Allow read/write on /domain */ | |
if (strcmp(path, DOMAINFILE) == 0) { | |
return 0; | |
} | |
printf("++++++++++++ OPEN(%s, %0X)\n", path, fi->flags); | |
if ((fi->flags & 3) != O_RDONLY) | |
return -EACCES; | |
return 0; | |
} | |
static int sshpub_read(const char *path, char *buf, size_t size, off_t offset, | |
struct fuse_file_info *fi) | |
{ | |
size_t len; | |
(void) fi; | |
char dnsbuf[BLEN]; | |
long targetlen = BLEN; | |
printf("++++++++++++ READ(%s, %X, size=%i, offset=%jd)\n\n", path, fi->flags, size, offset); | |
if (strcmp(path, DOMAINFILE) == 0) { | |
sprintf(buf, "%s\n", domain); | |
return (strlen(buf)); | |
} | |
if ((fi->flags & 3) != O_RDONLY) | |
return -EACCES; | |
if (getSSHkeys((char *)path+1, dnsbuf, targetlen) == 0) { | |
len = strlen(dnsbuf); | |
if (offset < len) { | |
if (offset + size > len) | |
size = len - offset; | |
memcpy(buf, dnsbuf + offset, size); | |
} else | |
size = 0; | |
printf("++++ read returns %i\n", size); | |
return size; | |
} | |
return -ENOENT; | |
} | |
static int sshpub_write(const char *path, const char *buf, size_t size, off_t offset, | |
struct fuse_file_info *fi) | |
{ | |
printf("WRITE CALLED with [%s]\n", path); | |
if (strcmp(path, DOMAINFILE) == 0) { | |
char *p; | |
if (domain) | |
free(domain); | |
domain = malloc(size+1); | |
strncpy(domain, buf, size); | |
domain[size] = 0; | |
// domain = strndup(buf, size); // FIXME | |
/* rstrip */ | |
for (p = domain + strlen(domain) - 1; p >= domain; p--) { | |
if (isspace(*p)) | |
*p = '\0'; | |
} | |
return size; | |
} | |
return -EACCES; | |
} | |
static int sshpub_mkdir(const char *path, mode_t mode) | |
{ | |
printf("MKDIR CALLED with [%s]\n", path); | |
servers[nservers] = strdup(path + 1); | |
nservers++; | |
return 0; | |
} | |
static int sshpub_creat(const char *path, mode_t mode, struct fuse_file_info *fi) | |
{ | |
printf("CREAT CALLED with [%s]\n", path); | |
if (strcmp(path, DOMAINFILE) == 0) { | |
return 0; | |
} | |
return -EACCES; | |
} | |
/* | |
* truncate() needed to support overwrite of /domains file | |
*/ | |
int sshpub_truncate(const char *path, off_t offset) | |
{ | |
printf("TRUNCATE CALLED with [%s]\n", path); | |
if (strcmp(path, DOMAINFILE) == 0) { | |
return 0; | |
} | |
return -EACCES; | |
} | |
/* | |
* FIXME: Program hangs on OS/X, possibly due to something wrong here | |
* "hangs" means bouncing ball for about 60s then program exits | |
*/ | |
int sshpub_statfs(const char *path, struct statvfs *vfs) | |
{ | |
printf("STATFS (%s)\n", path); | |
memset(vfs, sizeof(struct statvfs), 0); | |
vfs->f_bsize = 4096; | |
vfs->f_frsize = 4096; /* Fundamental file system block size */ | |
vfs->f_blocks = 512; /* Blocks on FS in units of f_frsize */ | |
vfs->f_bfree = 511; /* Free blocks */ | |
vfs->f_bavail = 511; /* Blocks available to non-root */ | |
vfs->f_files = 1024; /* Total inodes */ | |
vfs->f_ffree = 1020; /* Free inodes */ | |
vfs->f_favail = 1020; /* Free inodes for non-root */ | |
vfs->f_fsid = 0xbeefeaed; /* Filesystem ID */ | |
vfs->f_flag = 0x00L; /* Bit mask of values */ | |
vfs->f_namemax = 128; /* Max file name length */ | |
return 0; | |
} | |
static struct fuse_operations sshpub_oper = { | |
.getattr = sshpub_getattr, | |
.readdir = sshpub_readdir, | |
.open = sshpub_open, | |
.read = sshpub_read, | |
.mkdir = sshpub_mkdir, | |
.create = sshpub_creat, | |
.write = sshpub_write, | |
.truncate = sshpub_truncate, | |
.statfs = sshpub_statfs, | |
}; | |
int main(int argc, char *argv[]) | |
{ | |
domain = strdup("localhost"); | |
return fuse_main(argc, argv, &sshpub_oper); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment