Skip to content
Snippets Groups Projects
main.c 3.92 KiB
Newer Older
  • Learn to ignore specific revisions
  • Lars Seipel's avatar
    Lars Seipel committed
    // Copyright © 2019 Lars Seipel <ls@slrz.net>
    //
    // Derived from autofs (modules/lookup_sss.c, v5.1.6)
    //
    //   Copyright 2012 Ian Kent <raven@themaw.net>
    //   Copyright 2012 Red Hat, Inc.
    //
    // GNU General Public License v2.0+ (https://www.gnu.org/licenses/gpl-2.0.txt)
    
    #include <bsd/stdlib.h>
    #include <dlfcn.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/param.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <time.h>
    
    #include "arg.h"
    #include "log.h"
    #include "time.h"
    
    #define SSS_SO_NAME "libsss_autofs"
    #ifndef SSS_LIB_DIR
    
    #define SSS_LIB_DIR "/usr/lib/x86_64-linux-gnu/sssd/modules"
    
    Lars Seipel's avatar
    Lars Seipel committed
    #endif
    
    int _sss_setautomntent(const char *, void **);
    int _sss_getautomntent_r(char **, char **, void *);
    int _sss_getautomntbyname_r(char *, char **, void *);
    int _sss_endautomntent(void **);
    
    typedef int (*setautomntent_t)(const char *, void **);
    typedef int (*getautomntent_t)(char **, char **, void *);
    typedef int (*getautomntbyname_t)(char *, char **, void *);
    typedef int (*endautomntent_t)(void **);
    
    struct libsss_autofs {
    	void *dlhandle;
    	setautomntent_t setautomntent;
    	getautomntent_t getautomntent_r;
    	getautomntbyname_t getautomntbyname_r;
    	endautomntent_t endautomntent;
    };
    
    static int
    libsss_autofs_open(struct libsss_autofs *ctxt)
    {
    	char dlbuf[PATH_MAX];
    	char *estr;
    	void *dh;
    	size_t size;
    
    	size = snprintf(dlbuf, sizeof(dlbuf), "%s/%s.so", SSS_LIB_DIR,
    	                SSS_SO_NAME);
    	if (size >= sizeof(dlbuf)) {
    		errorf("sss library path too long");
    		return 1;
    	}
    
    	dh = dlopen(dlbuf, RTLD_LAZY);
    	if (!dh)
    		return 1;
    	ctxt->dlhandle = dh;
    
    	ctxt->setautomntent = (setautomntent_t)dlsym(dh, "_sss_setautomntent");
    	if (!ctxt->setautomntent)
    		goto lib_names_fail;
    
    	ctxt->getautomntent_r =
    	    (getautomntent_t)dlsym(dh, "_sss_getautomntent_r");
    	if (!ctxt->getautomntent_r)
    		goto lib_names_fail;
    
    	ctxt->getautomntbyname_r =
    	    (getautomntbyname_t)dlsym(dh, "_sss_getautomntbyname_r");
    	if (!ctxt->getautomntbyname_r)
    		goto lib_names_fail;
    
    	ctxt->endautomntent = (endautomntent_t)dlsym(dh, "_sss_endautomntent");
    	if (!ctxt->setautomntent)
    		goto lib_names_fail;
    
    	return 0;
    
    lib_names_fail:
    	if ((estr = dlerror()) == NULL)
    		errorf("failed to locate sss library entry points");
    	else
    		errorf("dlsym: %s", estr);
    	dlclose(dh);
    
    	return 1;
    }
    
    static int
    libsss_autofs_close(struct libsss_autofs *ctxt)
    {
    	int r;
    	if (r = dlclose(ctxt->dlhandle))
    		errorf("dlclose: %s", dlerror() ?: "<null>");
    
    	return r;
    }
    
    char *argv0;
    
    static void
    usage(int status)
    {
    	fprintf(stderr,
    	        "Usage: %s [options]\n"
    	        "  -h: show this help text\n"
    	        "  -v: be verbose\n",
    	        argv0);
    
    	exit(status);
    }
    
    static const int64_t base_delay = 100 * Millisecond;
    static const int64_t max_delay = 2 * Second;
    
    int
    main(int argc, char **argv)
    {
    	const char *mapname = "auto.master";
    	int vflag = 0;
    	char fmtbuf[16];
    
    	ARGBEGIN
    	{
    	case 'h':
    		usage(0);
    		break;
    	case 'v':
    		vflag++;
    		break;
    	default:
    		usage(2);
    	}
    	ARGEND
    
    	if (*argv)
    		mapname = *argv;
    
    	struct libsss_autofs sss_autofs;
    	void *ctx = NULL;
    
    	int r = libsss_autofs_open(&sss_autofs);
    	if (r)
    		fatalf("libsss_autofs_open: %d", r);
    
    	int64_t delay = base_delay;
    	for (int i = 0; i < 1000; i++) {
    		r = sss_autofs.setautomntent(mapname, &ctx);
    		if (r == 0)
    			break;
    
    		ctx = NULL;
    
    		int64_t backoff_nsec = delay + arc4random_uniform(delay / 2);
    		struct timespec ts = totimespec(backoff_nsec);
    		warnf("setautomntent: %d (retry in %s)", r,
    		      fmtduration(fmtbuf, sizeof fmtbuf, backoff_nsec));
    		nanosleep(&ts, NULL);
    		delay <<= 1;
    		if (delay > max_delay)
    			delay = max_delay;
    	}
    	if (!ctx)
    		goto Out;
    
    	char *key = NULL, *value = NULL;
    	while ((r = sss_autofs.getautomntent_r(&key, &value, ctx)) == 0) {
    		if (vflag)
    			printf("%s → %s\n", key ?: "<null>", value ?: "<null>");
    		free(key);
    		free(value);
    		key = value = NULL;
    	}
    	r = 0;
    
    Out:
    	if (ctx)
    		sss_autofs.endautomntent(&ctx);
    	libsss_autofs_close(&sss_autofs);
    
    	return r;
    }