Blame libuser.c

Packit 64c699
/*
Packit 64c699
 * Copyright Red Hat, Inc., 2002, 2006, 2015.
Packit 64c699
 *
Packit 64c699
 * Redistribution and use in source and binary forms, with or without
Packit 64c699
 * modification, are permitted provided that the following conditions
Packit 64c699
 * are met:
Packit 64c699
 * 1. Redistributions of source code must retain the above copyright
Packit 64c699
 *    notice, and the entire permission notice in its entirety,
Packit 64c699
 *    including the disclaimer of warranties.
Packit 64c699
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 64c699
 *    notice, this list of conditions and the following disclaimer in the
Packit 64c699
 *    documentation and/or other materials provided with the distribution.
Packit 64c699
 * 3. The name of the author may not be used to endorse or promote
Packit 64c699
 *    products derived from this software without specific prior
Packit 64c699
 *    written permission.
Packit 64c699
 *
Packit 64c699
 * ALTERNATIVELY, this product may be distributed under the terms of
Packit 64c699
 * the GNU Public License, in which case the provisions of the GPL are
Packit 64c699
 * required INSTEAD OF the above restrictions.  (This clause is
Packit 64c699
 * necessary due to a potential bad interaction between the GPL and
Packit 64c699
 * the restrictions contained in a BSD-style copyright.)
Packit 64c699
 *
Packit 64c699
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
Packit 64c699
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit 64c699
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit 64c699
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
Packit 64c699
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit 64c699
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit 64c699
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 64c699
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
Packit 64c699
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit 64c699
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
Packit 64c699
 * OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 64c699
 */
Packit 64c699
Packit 64c699
/*
Packit 64c699
 * This file contains libuser wrappers with prototypes which match the
Packit 64c699
 * declarations in pwdb.h.  Where possible, behavior is kept as close
Packit 64c699
 * to that of the previous versions as possible.
Packit 64c699
 */
Packit 64c699
Packit 64c699
#include "config.h"
Packit 64c699
Packit 64c699
#include <string.h>
Packit 64c699
#include <unistd.h>
Packit 64c699
#include <stdlib.h>
Packit 64c699
#include <time.h>
Packit 64c699
Packit 64c699
/* GValueArray is a part of external API of libuser; warnings about it being
Packit 64c699
   deprecated do no good. */
Packit 64c699
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30
Packit 64c699
Packit 64c699
#include <libuser/user.h>
Packit 64c699
#include <libintl.h>
Packit 64c699
#include "pwdb.h"
Packit 64c699
Packit 64c699
extern const char *progname;
Packit 64c699
Packit 64c699
#define CHECK_ERROR(x) \
Packit 64c699
if (x != NULL) { \
Packit 64c699
	fprintf(stderr, "%s: Libuser error at line: %d - %s.\n", \
Packit 64c699
		progname, __LINE__, lu_strerror(x)); \
Packit 64c699
	lu_error_free(&x); \
Packit 64c699
	return -1; \
Packit 64c699
}
Packit 64c699
Packit 64c699
static struct lu_context *libuser = NULL;
Packit 64c699
Packit 64c699
/* Shut down libuser. */
Packit 64c699
static void
Packit 64c699
shutdown_libuser(void)
Packit 64c699
{
Packit 64c699
	lu_end(libuser);
Packit 64c699
	libuser = NULL;
Packit 64c699
}
Packit 64c699
Packit 64c699
/* Start up the library, suggesting the name of the user which was
Packit 64c699
 * passed in as the name the library should use if it needs to
Packit 64c699
 * authenticate to data sources. */
Packit 64c699
static void
Packit 64c699
startup_libuser(const char *user)
Packit 64c699
{
Packit 64c699
	struct lu_error *error = NULL;
Packit 64c699
	if (libuser != NULL) {
Packit 64c699
		shutdown_libuser();
Packit 64c699
	}
Packit 64c699
	libuser = lu_start(user, lu_user, NULL, NULL,
Packit 64c699
			   lu_prompt_console, NULL, &error);
Packit 64c699
	if (error != NULL || libuser == NULL) {
Packit 64c699
		fprintf(stderr,
Packit 64c699
			_("%s: libuser initialization error:"), progname);
Packit 64c699
	}
Packit 64c699
	if (error != NULL) {
Packit 64c699
		fprintf(stderr,
Packit 64c699
			" %s\n", lu_strerror(error));
Packit 64c699
		_exit(1);
Packit 64c699
	}
Packit 64c699
	if (libuser == NULL) {
Packit 64c699
		fprintf(stderr,
Packit 64c699
			" unknown error\n");
Packit 64c699
		_exit(1);
Packit 64c699
	}
Packit 64c699
}
Packit 64c699
Packit 64c699
/* Lock an account. */
Packit 64c699
int
Packit 64c699
pwdb_lock_password(const char *username)
Packit 64c699
{
Packit 64c699
	int retval = 1;
Packit 64c699
	struct lu_ent *ent;
Packit 64c699
	struct lu_error *error = NULL;
Packit 64c699
	gboolean started = FALSE;
Packit 64c699
	if (libuser == NULL) {
Packit 64c699
		startup_libuser("root");
Packit 64c699
		started = TRUE;
Packit 64c699
	}
Packit 64c699
	ent = lu_ent_new();
Packit 64c699
	if (lu_user_lookup_name(libuser, username, ent, &error)) {
Packit 64c699
		if (lu_user_lock(libuser, ent, &error)) {
Packit 64c699
			retval = 0;
Packit 64c699
		}
Packit 64c699
	}
Packit 64c699
	lu_ent_free(ent);
Packit 64c699
	CHECK_ERROR(error);
Packit 64c699
	if (started) {
Packit 64c699
		shutdown_libuser();
Packit 64c699
	}
Packit 64c699
	return retval;
Packit 64c699
}
Packit 64c699
Packit 64c699
int
Packit 64c699
pwdb_unlock_password(const char *username, int force)
Packit 64c699
{
Packit 64c699
	int retval = 1, i;
Packit 64c699
	struct lu_ent *ent;
Packit 64c699
	struct lu_error *error = NULL;
Packit 64c699
	const char *current = NULL;
Packit 64c699
	gboolean started = FALSE;
Packit 64c699
	if (libuser == NULL) {
Packit 64c699
		startup_libuser("root");
Packit 64c699
		started = TRUE;
Packit 64c699
	}
Packit 64c699
	ent = lu_ent_new();
Packit 64c699
	if (lu_user_lookup_name(libuser, username, ent, &error)) {
Packit 64c699
		current = lu_ent_get_first_value_strdup(ent, LU_SHADOWPASSWORD);
Packit 64c699
		if (current == NULL)
Packit 64c699
			lu_ent_get_first_value_strdup(ent, LU_USERPASSWORD);
Packit 64c699
		if (current && (force == 0)) {
Packit 64c699
			/* Search for a non-locking character. */
Packit 64c699
			for (i = 0; (current[i] == '!'); i++) {
Packit 64c699
				/*nothing */
Packit 64c699
			};
Packit 64c699
			/* If the first non-locking character is the end of the
Packit 64c699
			 * string, */
Packit 64c699
			if (current[i] == '\0') {
Packit 64c699
				fprintf(stderr, "%s: %s\n", progname,
Packit 64c699
					_("Warning: unlocked password would be empty."));
Packit 64c699
				/* warn the admin, because this is probably a
Packit 64c699
				 * bad idea. */
Packit 64c699
				retval = -2;
Packit 64c699
			}
Packit 64c699
		}
Packit 64c699
		if (retval != -2) {
Packit 64c699
			/* Go blind, or force it. */
Packit 64c699
			if (lu_user_unlock(libuser, ent, &error)) {
Packit 64c699
				retval = 0;
Packit 64c699
			}
Packit 64c699
		}
Packit 64c699
	}
Packit 64c699
	lu_ent_free(ent);
Packit 64c699
	CHECK_ERROR(error);
Packit 64c699
	if (started) {
Packit 64c699
		shutdown_libuser();
Packit 64c699
	}
Packit 64c699
	return retval;
Packit 64c699
}
Packit 64c699
Packit 64c699
/* Try to remove a user's password.  Note that some of the underlying modules
Packit 64c699
 * libuser uses don't support this. */
Packit 64c699
int
Packit 64c699
pwdb_clear_password(const char *username)
Packit 64c699
{
Packit 64c699
	int retval = 1;
Packit 64c699
	struct lu_ent *ent;
Packit 64c699
	struct lu_error *error = NULL;
Packit 64c699
	gboolean started = FALSE;
Packit 64c699
	if (libuser == NULL) {
Packit 64c699
		startup_libuser("root");
Packit 64c699
		started = TRUE;
Packit 64c699
	}
Packit 64c699
	ent = lu_ent_new();
Packit 64c699
	if (lu_user_lookup_name(libuser, username, ent, &error)) {
Packit 64c699
		const char *current;
Packit 64c699
Packit 64c699
		current = lu_ent_get_first_value_strdup(ent, LU_SHADOWPASSWORD);
Packit 64c699
		if (current == NULL)
Packit 64c699
			lu_ent_get_first_value_strdup(ent, LU_USERPASSWORD);
Packit 64c699
		if (current != NULL && *current == '!')
Packit 64c699
			/* Just note this, do not abort, do not change exit
Packit 64c699
			 * code; if someone wants to use -d at all, let's not
Packit 64c699
			 * break their scripts. */
Packit 64c699
			fprintf(stderr, "%s: %s\n", progname,
Packit 64c699
				_("Note: deleting a password also unlocks the "
Packit 64c699
				  "password."));
Packit 64c699
		if (lu_user_removepass(libuser, ent, &error)) {
Packit 64c699
			retval = 0;
Packit 64c699
		}
Packit 64c699
	}
Packit 64c699
	lu_ent_free(ent);
Packit 64c699
	CHECK_ERROR(error);
Packit 64c699
	if (started) {
Packit 64c699
		shutdown_libuser();
Packit 64c699
	}
Packit 64c699
	return retval;
Packit 64c699
}
Packit 64c699
Packit 64c699
static long long
Packit 64c699
ent_value_int64(struct lu_ent *ent, const char *attribute)
Packit 64c699
{
Packit 64c699
	GValueArray *values;
Packit 64c699
	GValue *value;
Packit 64c699
        value = NULL;
Packit 64c699
        values = lu_ent_get(ent, attribute);
Packit 64c699
        if (values) {
Packit 64c699
		value = g_value_array_get_nth(values, 0);
Packit 64c699
	}
Packit 64c699
	if (value) {
Packit 64c699
		if (G_VALUE_HOLDS_STRING(value)) {
Packit 64c699
			return strtoll(g_value_get_string(value), NULL, 10);
Packit 64c699
		}
Packit 64c699
	        else if (G_VALUE_HOLDS_LONG(value)) {
Packit 64c699
	                return g_value_get_long(value);
Packit 64c699
	        }
Packit 64c699
	        else if (G_VALUE_HOLDS_INT64(value)) {
Packit 64c699
	                return (long long)g_value_get_int64(value);
Packit 64c699
		}
Packit 64c699
        }
Packit 64c699
        return -1;
Packit 64c699
}
Packit 64c699
Packit 64c699
int
Packit 64c699
pwdb_display_status(const char *username)
Packit 64c699
{
Packit 64c699
	int retval = 1;
Packit 64c699
	struct lu_ent *ent;
Packit 64c699
	struct lu_error *error = NULL;
Packit 64c699
	char *current;
Packit 64c699
	char *realname;
Packit 64c699
	const char *msg;
Packit 64c699
	int shadow = 1;
Packit 64c699
	time_t sp_lstchg = 0;
Packit 64c699
	long long sp_min = 0;
Packit 64c699
	long long sp_max = 0;
Packit 64c699
	long long sp_warn = 0;
Packit 64c699
	long long sp_inact= 0;
Packit 64c699
	char date[80];
Packit 64c699
	const char *status;
Packit 64c699
	struct tm tm;
Packit 64c699
Packit 64c699
	startup_libuser(username);
Packit 64c699
Packit 64c699
	ent = lu_ent_new();
Packit 64c699
	if (lu_user_lookup_name(libuser, username, ent, &error)) {
Packit 64c699
		realname = lu_ent_get_first_value_strdup(ent, LU_USERNAME);
Packit 64c699
		if (realname == NULL) {
Packit 64c699
			fprintf(stderr, "%s: %s\n", progname,
Packit 64c699
				_("Corrupted passwd entry."));
Packit 64c699
			goto bail;
Packit 64c699
		}
Packit 64c699
		current = lu_ent_get_first_value_strdup(ent, LU_SHADOWPASSWORD);
Packit 64c699
		if (current == NULL) {
Packit 64c699
			shadow = 0;
Packit Service 2bde9a
			current = lu_ent_get_first_value_strdup(ent, LU_USERPASSWORD);
Packit 64c699
		} else {
Packit 64c699
			sp_lstchg = (time_t) ent_value_int64(ent, LU_SHADOWLASTCHANGE);
Packit 64c699
			sp_min = ent_value_int64(ent, LU_SHADOWMIN);
Packit 64c699
			sp_max = ent_value_int64(ent, LU_SHADOWMAX);
Packit 64c699
			sp_warn = ent_value_int64(ent, LU_SHADOWWARNING);
Packit 64c699
			sp_inact = ent_value_int64(ent, LU_SHADOWINACTIVE);
Packit 64c699
		}
Packit 64c699
		if (current) {
Packit 64c699
			status = "PS";
Packit 64c699
			if (strlen(current) == 0) {
Packit 64c699
				msg = _("Empty password.");
Packit 64c699
				status = "NP";
Packit 64c699
			} else if (current[0] == '!') {
Packit 64c699
				msg = _("Password locked.");
Packit 64c699
				status = "LK";
Packit 64c699
			} else if (current[0] == '$') {
Packit 64c699
				if (strncmp(current, "$1$", 3) == 0) {
Packit 64c699
					msg = _("Password set, MD5 crypt.");
Packit 64c699
				} else if (strncmp(current, "$2a$", 4) ==
Packit 64c699
					   0) {
Packit 64c699
					msg = _("Password set, blowfish crypt.");
Packit 64c699
				} else if (strncmp(current, "$5$", 3) ==
Packit 64c699
					   0) {
Packit 64c699
					msg = _("Password set, SHA256 crypt.");
Packit 64c699
				} else if (strncmp(current, "$6$", 3) ==
Packit 64c699
					   0) {
Packit 64c699
					msg = _("Password set, SHA512 crypt.");
Packit 64c699
				} else {
Packit 64c699
					msg = _("Password set, unknown crypt variant.");
Packit 64c699
				}
Packit 64c699
			} else if (strlen(current) < 11) {
Packit 64c699
				msg = _("Alternate authentication scheme in use.");
Packit 64c699
				if (current[0] == '*' || current[0] == 'x') {
Packit 64c699
					status = "LK";
Packit 64c699
				}
Packit 64c699
			} else {
Packit 64c699
				msg = _("Password set, DES crypt.");
Packit 64c699
			}
Packit 64c699
			if (shadow) {
Packit 64c699
				sp_lstchg = sp_lstchg * 24L * 3600L;
Packit 64c699
				localtime_r(&sp_lstchg, &tm;;
Packit 64c699
				strftime(date, sizeof(date), "%Y-%m-%d", &tm;;
Packit 64c699
				printf("%s %s %s %lld %lld %lld %lld (%s)\n", realname, status,
Packit 64c699
					date, sp_min, sp_max, sp_warn, sp_inact, msg);
Packit 64c699
			} else {
Packit 64c699
				printf("%s %s (%s)\n", realname, status, msg);
Packit 64c699
			}
Packit 64c699
			g_free(current);
Packit 64c699
		} else {
Packit 64c699
			printf(_("No password set.\n"));
Packit 64c699
		}
Packit 64c699
		g_free(realname);
Packit 64c699
		retval = 0;
Packit 64c699
	} else {
Packit 64c699
		printf(_("Unknown user.\n"));
Packit 64c699
		retval = 2;
Packit 64c699
	}
Packit 64c699
bail:
Packit 64c699
	CHECK_ERROR(error);
Packit 64c699
Packit 64c699
	shutdown_libuser();
Packit 64c699
	return retval;
Packit 64c699
}
Packit 64c699
Packit 64c699
int
Packit 64c699
pwdb_update_gecos(const char *username, const char *gecos)
Packit 64c699
{
Packit 64c699
	int retval = 1;
Packit 64c699
	struct lu_ent *ent;
Packit 64c699
	struct lu_error *error = NULL;
Packit 64c699
Packit 64c699
	startup_libuser(username);
Packit 64c699
Packit 64c699
	ent = lu_ent_new();
Packit 64c699
	if (lu_user_lookup_name(libuser, username, ent, &error)) {
Packit 64c699
		lu_ent_set_string(ent, LU_GECOS, gecos);
Packit 64c699
Packit 64c699
		if (lu_user_modify(libuser, ent, &error)) {
Packit 64c699
			retval = 0;
Packit 64c699
		}
Packit 64c699
	}
Packit 64c699
Packit 64c699
	CHECK_ERROR(error);
Packit 64c699
Packit 64c699
	shutdown_libuser();
Packit 64c699
	return retval;
Packit 64c699
}
Packit 64c699
Packit 64c699
int
Packit 64c699
pwdb_update_shell(const char *username, const char *shell)
Packit 64c699
{
Packit 64c699
	int retval = 1;
Packit 64c699
	struct lu_ent *ent;
Packit 64c699
	struct lu_error *error = NULL;
Packit 64c699
Packit 64c699
	startup_libuser(username);
Packit 64c699
Packit 64c699
	ent = lu_ent_new();
Packit 64c699
	if (lu_user_lookup_name(libuser, username, ent, &error)) {
Packit 64c699
		lu_ent_set_string(ent, LU_LOGINSHELL, shell);
Packit 64c699
Packit 64c699
		if (lu_user_modify(libuser, ent, &error)) {
Packit 64c699
			retval = 0;
Packit 64c699
		}
Packit 64c699
	}
Packit 64c699
Packit 64c699
	CHECK_ERROR(error);
Packit 64c699
Packit 64c699
	shutdown_libuser();
Packit 64c699
	return retval;
Packit 64c699
}
Packit 64c699
Packit 64c699
Packit 64c699
int
Packit 64c699
pwdb_update_aging(const char *username,
Packit 64c699
		  long min, long max, long warn, long inact, long lastchg)
Packit 64c699
{
Packit 64c699
	int retval = 1;
Packit 64c699
	struct lu_ent *ent;
Packit 64c699
	struct lu_error *error = NULL;
Packit 64c699
Packit 64c699
	startup_libuser(username);
Packit 64c699
Packit 64c699
	ent = lu_ent_new();
Packit 64c699
	if (lu_user_lookup_name(libuser, username, ent, &error)) {
Packit 64c699
		if (!lu_ent_get(ent, LU_SHADOWMIN) &&
Packit 64c699
		    !lu_ent_get(ent, LU_SHADOWMAX) &&
Packit 64c699
		    !lu_ent_get(ent, LU_SHADOWWARNING) &&
Packit 64c699
		    !lu_ent_get(ent, LU_SHADOWINACTIVE)) {
Packit 64c699
			fprintf(stderr, _("%s: user account has no support "
Packit 64c699
					  "for password aging.\n"), progname);
Packit 64c699
			shutdown_libuser();
Packit 64c699
			return retval;
Packit 64c699
		}
Packit 64c699
Packit 64c699
		if (min != -2)
Packit 64c699
			lu_ent_set_long(ent, LU_SHADOWMIN, min);
Packit 64c699
		if (max != -2)
Packit 64c699
			lu_ent_set_long(ent, LU_SHADOWMAX, max);
Packit 64c699
		if (warn != -2)
Packit 64c699
			lu_ent_set_long(ent, LU_SHADOWWARNING, warn);
Packit 64c699
		if (inact != -2)
Packit 64c699
			lu_ent_set_long(ent, LU_SHADOWINACTIVE, inact);
Packit 64c699
		if (lastchg != -2)
Packit 64c699
			lu_ent_set_long(ent, LU_SHADOWLASTCHANGE, lastchg);
Packit 64c699
Packit 64c699
		if (lu_user_modify(libuser, ent, &error)) {
Packit 64c699
			retval = 0;
Packit 64c699
		}
Packit 64c699
	}
Packit 64c699
Packit 64c699
	CHECK_ERROR(error);
Packit 64c699
Packit 64c699
	shutdown_libuser();
Packit 64c699
	return retval;
Packit 64c699
}