view src/util/authtest.c @ 9984:097588a7903c HEAD

lib-auth: Changed API to connect to only a single specified auth socket. Login processes now always connect to socket called "auth".
author Timo Sirainen <tss@iki.fi>
date Wed, 07 Oct 2009 17:46:14 -0400
parents 87c40d1d2b6c
children
line wrap: on
line source

/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "base64.h"
#include "str.h"
#include "master-service.h"
#include "auth-client.h"
#include "auth-server-connection.h"
#include "auth-master.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

struct authtest_input {
	const char *username;
	const char *password;
	struct auth_user_info info;
};

static const char *auth_socket_path = NULL;

static int authtest_userdb(const struct authtest_input *input)
{
	struct auth_master_connection *conn;
	pool_t pool;
	struct auth_user_reply reply;
	const char *const *fields;
	unsigned int i, count;
	int ret;

	if (auth_socket_path == NULL)
		auth_socket_path = PKG_RUNDIR"/auth-userdb";

	pool = pool_alloconly_create("auth master lookup", 1024);

	conn = auth_master_init(auth_socket_path, FALSE);
	ret = auth_master_user_lookup(conn, input->username, &input->info,
				      pool, &reply);
	if (ret < 0)
		i_fatal("userdb lookup failed");
	else if (ret == 0) {
		printf("userdb lookup: user %s doesn't exist\n",
		       input->username);
	} else {
		printf("userdb: %s\n", input->username);

		if (reply.uid != (uid_t)-1)
			printf("uid   : %s\n", dec2str(reply.uid));
		if (reply.gid != (gid_t)-1)
			printf("gid   : %s\n", dec2str(reply.gid));
		if (reply.user != NULL)
			printf("user  : %s\n", reply.user);
		if (reply.home != NULL)
			printf("home  : %s\n", reply.home);
		if (reply.chroot != NULL)
			printf("chroot: %s\n", reply.chroot);
		fields = array_get(&reply.extra_fields, &count);
		if (count > 0) {
			printf("extra fields:\n");
			for (i = 0; i < count; i++)
				printf("  %s\n", fields[i]);
		}
	}
	auth_master_deinit(&conn);
	return ret == 0 ? 1 : 0;
}

static void
auth_callback(struct auth_client_request *request ATTR_UNUSED,
	      enum auth_request_status status,
	      const char *data_base64 ATTR_UNUSED,
	      const char *const *args, void *context)
{
	const struct authtest_input *input = context;

	if (!io_loop_is_running(current_ioloop))
		return;

	if (status == 0)
		i_fatal("passdb expects SASL continuation");

	if (status < 0)
		printf("passdb: %s auth failed\n", input->username);
	else
		printf("passdb: %s auth succeeded\n", input->username);

	if (*args != NULL) {
		printf("extra fields:\n");
		for (; *args != NULL; args++)
			printf("  %s\n", *args);
	}
	io_loop_stop(current_ioloop);
}

static void auth_connected(struct auth_client *client,
			   bool connected, void *context)
{
	struct authtest_input *input = context;
	struct auth_request_info info;
	string_t *init_resp, *base64_resp;

	if (!connected)
		i_fatal("Couldn't connect to auth socket");

	init_resp = t_str_new(128);
	str_append_c(init_resp, '\0');
	str_append(init_resp, input->username);
	str_append_c(init_resp, '\0');
	str_append(init_resp, input->password);

	base64_resp = t_str_new(128);
	base64_encode(str_data(init_resp), str_len(init_resp), base64_resp);

	memset(&info, 0, sizeof(info));
	info.mech = "PLAIN";
	info.service = input->info.service;
	info.local_ip = input->info.local_ip;
	info.local_port = input->info.local_port;
	info.remote_ip = input->info.remote_ip;
	info.remote_port = input->info.remote_port;
	info.initial_resp_base64 = str_c(base64_resp);

	(void)auth_client_request_new(client, &info,
				      auth_callback, input);
}

static int
authtest_passdb(struct authtest_input *input)
{
	struct auth_client *client;

	if (auth_socket_path == NULL)
		auth_socket_path = PKG_RUNDIR"/auth-client";

	client = auth_client_init(auth_socket_path, getpid(), FALSE);
	auth_client_set_connect_notify(client, auth_connected, input);

	io_loop_run(current_ioloop);

	auth_client_set_connect_notify(client, NULL, NULL);
	auth_client_deinit(&client);
	return 0;
}

static void auth_user_info_parse(struct auth_user_info *info, const char *arg)
{
	if (strncmp(arg, "service=", 8) == 0)
		info->service = arg + 8;
	else if (strncmp(arg, "lip=", 4) == 0) {
		if (net_addr2ip(arg + 4, &info->local_ip) < 0)
			i_fatal("lip: Invalid ip");
	} else if (strncmp(arg, "rip=", 4) == 0) {
		if (net_addr2ip(arg + 4, &info->remote_ip) < 0)
			i_fatal("rip: Invalid ip");
	} else if (strncmp(arg, "lport=", 6) == 0) {
		info->local_port = atoi(arg + 6);
	} else if (strncmp(arg, "rport=", 6) == 0) {
		info->remote_port = atoi(arg + 6);
	} else {
		i_fatal("Unknown -x argument: %s", arg);
	}
}

static void usage(void)
{
	i_fatal(
"usage: authtest [-a <auth socket path>] [-x <auth info>] <user> [<password]");
}

int main(int argc, char *argv[])
{
	const char *getopt_str;
	struct authtest_input input;
	int c, ret;

	memset(&input, 0, sizeof(input));
	input.info.service = "authtest";

	master_service = master_service_init("authtest",
					     MASTER_SERVICE_FLAG_STANDALONE,
					     argc, argv);
	getopt_str = t_strconcat("a:x:", master_service_getopt_string(), NULL);
	while ((c = getopt(argc, argv, getopt_str)) > 0) {
		switch (c) {
		case 'a':
			auth_socket_path = optarg;
			break;
		case 'x':
			auth_user_info_parse(&input.info, optarg);
			break;
		default:
			if (!master_service_parse_option(master_service,
							 c, optarg))
				usage();
		}
	}
	if (optind == argc)
		usage();

	input.username = argv[optind++];
	if (argv[optind] == NULL)
		ret = authtest_userdb(&input);
	else {
		input.password = argv[optind];
		ret = authtest_passdb(&input);
	}
	master_service_deinit(&master_service);
	return ret;
}