Blame libuser.c.S-output

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