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