/*
* PWDB.C
*
* Some wrapper functions for libpwdb interfaces.
*/
/*
* Copyright Red Hat, Inc., 1998, 1999, 2002.
*
* 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.
*/
/*
* Written by Cristian Gafton <gafton@redhat.com>
*/
#include "config.h"
#include "pwdb.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pwdb/pwdb_public.h>
#include <pwdb/pwdb_shadow.h>
extern const char *progname;
#define CHECK_ERROR(x) if (x != PWDB_SUCCESS) { \
fprintf(stderr, "%s: Pwdb error at line: %d - %s.\n", \
progname, __LINE__, pwdb_strerror(x)); /* that is an old trick... */ \
if (_pwdb != (struct pwdb *)NULL) \
pwdb_delete(&_pwdb); \
pwdb_end(); \
return -1; \
}
int
pwdb_lock_password(const char *username)
{
const struct pwdb *_pwdb = NULL;
const struct pwdb_entry *_pwe = NULL;
char *new_pass, *t;
int retval, flags, new_len;
retval = pwdb_start();
if (retval != PWDB_SUCCESS) {
return -1;
}
retval = pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN,
&_pwdb);
CHECK_ERROR(retval);
retval = pwdb_get_entry(_pwdb, "passwd", &_pwe);
if (_pwe == (struct pwdb_entry *) NULL) {
/* this user does not have a password set */
pwdb_delete(&_pwdb);
pwdb_end();
return -1;
}
new_pass = alloca(_pwe->length + 3);
t = (char *) _pwe->value;
if (*t == '!') {
/* already locked... */
return 0;
}
/*
* Avoid creating single char '!' crypted passwords that could
* be interpreted as shadow or some other crap
*/
new_len = _pwe->length + 2;
if (_pwe->length < 3) {
snprintf(new_pass, new_len++, "!!%s", t);
} else {
snprintf(new_pass, new_len, "!%s", t);
}
retval = pwdb_set_entry(_pwdb, "passwd", new_pass, new_len,
NULL, NULL, 0);
CHECK_ERROR(retval);
retval = pwdb_entry_delete(&_pwe);
CHECK_ERROR(retval);
retval = pwdb_flags("user", _pwdb->source, &flags);
CHECK_ERROR(retval);
if (flags & PWDB_F_NOUPDATE) {
fprintf(stderr,
"%s: insufficient privilege to complete operation\n",
progname);
pwdb_delete(&_pwdb);
pwdb_end();
return -1;
}
retval = pwdb_replace("user", _pwdb->source, username,
PWDB_ID_UNKNOWN, &_pwdb);
CHECK_ERROR(retval);
retval = pwdb_delete(&_pwdb);
CHECK_ERROR(retval);
pwdb_end();
return retval;
}
int
pwdb_unlock_password(const char *username, int force)
{
const struct pwdb *_pwdb = NULL;
const struct pwdb_entry *_pwe = NULL;
char *t;
int retval, flags;
retval = pwdb_start();
if (retval != PWDB_SUCCESS) {
return -1;
}
retval = pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN,
&_pwdb);
CHECK_ERROR(retval);
retval = pwdb_get_entry(_pwdb, "passwd", &_pwe);
CHECK_ERROR(retval);
t = (char *) _pwe->value;
if (*t != '!') {
/* already unlocked... */
pwdb_delete(&_pwdb);
pwdb_end();
return 0;
}
while (*t == '!') {
if (_pwe->length <= 1) {
t = "";
_pwe->length = 1;
break;
}
/* try to remove as many ! signs as we find... */
if (_pwe->length == 2) {
/* avoid leaving empty passwords */
if (force) {
t++; /* The user really knows what is going on... */
_pwe->length--;
continue;
} else {
fprintf(stderr,
"Warning: unlocked password for %s is the empty string.\n"
"Use the -f flag to force the creation of a passwordless account.\n",
username);
pwdb_delete(&_pwdb);
pwdb_end();
return -2;
}
}
/* we have plenty of room to unlock it... */
t++;
_pwe->length--;
}
retval = pwdb_set_entry(_pwdb, "passwd", t,
_pwe->length, NULL, NULL, 0);
CHECK_ERROR(retval);
retval = pwdb_entry_delete(&_pwe);
CHECK_ERROR(retval);
retval = pwdb_flags("user", _pwdb->source, &flags);
CHECK_ERROR(retval);
if (flags & PWDB_F_NOUPDATE) {
fprintf(stderr,
"%s: insufficient privilege to complete operation\n",
progname);
pwdb_delete(&_pwdb);
pwdb_end();
return -1;
}
retval = pwdb_replace("user", _pwdb->source, username,
PWDB_ID_UNKNOWN, &_pwdb);
CHECK_ERROR(retval);
retval = pwdb_delete(&_pwdb);
CHECK_ERROR(retval);
pwdb_end();
return retval;
}
int
pwdb_clear_password(const char *username)
{
const struct pwdb *_pwdb = NULL;
int retval, flags;
retval = pwdb_start();
if (retval != PWDB_SUCCESS) {
return -1;
}
retval = pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN,
&_pwdb);
CHECK_ERROR(retval);
retval = pwdb_flags("user", _pwdb->source, &flags);
CHECK_ERROR(retval);
if (flags & PWDB_F_NOUPDATE) {
fprintf(stderr,
"%s: insufficient privilege to complete operation\n",
progname);
pwdb_delete(&_pwdb);
pwdb_end();
return -1;
}
retval = pwdb_set_entry(_pwdb, "passwd", "", 1, NULL, NULL, 0);
CHECK_ERROR(retval);
retval = pwdb_replace("user", _pwdb->source, username,
PWDB_ID_UNKNOWN, &_pwdb);
CHECK_ERROR(retval);
retval = pwdb_delete(&_pwdb);
CHECK_ERROR(retval);
pwdb_end();
return retval;
}
int
pwdb_display_status(const char *username)
{
const struct pwdb *_pwdb = NULL;
const struct pwdb_entry *_pwe = NULL;
char *t;
int retval;
retval = pwdb_start();
if (retval != PWDB_SUCCESS) {
return -1;
}
retval = pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN,
&_pwdb);
CHECK_ERROR(retval);
retval = pwdb_get_entry(_pwdb, "passwd", &_pwe);
if (_pwe == (struct pwdb_entry *) NULL) {
/* this user does not have a password set */
printf("No Password set.\n");
pwdb_delete(&_pwdb);
pwdb_end();
return 0;
}
t = (char *) _pwe->value;
if (strlen(t) == 0) {
printf("Empty password.\n");
pwdb_delete(&_pwdb);
pwdb_end();
return 0;
}
switch (*t) {
case '!':
printf("Locked password.\n");
break;
case '$':
if (strncmp(t, "$1$", 3) == 0) {
printf("Password set, MD5 encryption\n");
} else {
printf("Password set, unknown encryption\n");
}
break;
default:
printf("Password set, DES encryption\n");
}
retval = pwdb_entry_delete(&_pwe);
CHECK_ERROR(retval);
retval = pwdb_delete(&_pwdb);
CHECK_ERROR(retval);
pwdb_end();
return retval;
}
int
pwdb_update_gecos(const char *username, const char *gecos)
{
const struct pwdb *_pwdb = NULL;
int retval, flags;
/* Now update the user entry */
retval = pwdb_start();
if (retval != PWDB_SUCCESS) {
return -1;
}
retval = pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN,
&_pwdb);
CHECK_ERROR(retval);
retval = pwdb_flags("user", _pwdb->source, &flags);
CHECK_ERROR(retval);
if (flags & PWDB_F_NOUPDATE) {
fprintf(stderr,
"%s: insufficient privilege to complete operation\n",
progname);
pwdb_delete(&_pwdb);
pwdb_end();
return -1;
}
retval = pwdb_set_entry(_pwdb, "gecos", gecos, 1 + strlen(gecos),
NULL, NULL, 0);
CHECK_ERROR(retval);
retval = pwdb_replace("user", _pwdb->source, username,
PWDB_ID_UNKNOWN, &_pwdb);
CHECK_ERROR(retval);
retval = pwdb_delete(&_pwdb);
CHECK_ERROR(retval);
pwdb_end();
return retval;
}
int
pwdb_update_shell(const char *username, const char *shell)
{
const struct pwdb *_pwdb = NULL;
int retval, flags;
/* Now update the user entry */
retval = pwdb_start();
if (retval != PWDB_SUCCESS) {
return -1;
}
retval = pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN,
&_pwdb);
CHECK_ERROR(retval);
retval = pwdb_flags("user", _pwdb->source, &flags);
CHECK_ERROR(retval);
if (flags & PWDB_F_NOUPDATE) {
fprintf(stderr,
"%s: insufficient privilege to complete operation\n",
progname);
pwdb_delete(&_pwdb);
pwdb_end();
return -1;
}
retval = pwdb_set_entry(_pwdb, "shell", shell, 1 + strlen(shell),
NULL, NULL, 0);
CHECK_ERROR(retval);
retval = pwdb_replace("user", _pwdb->source, username,
PWDB_ID_UNKNOWN, &_pwdb);
CHECK_ERROR(retval);
retval = pwdb_delete(&_pwdb);
CHECK_ERROR(retval);
pwdb_end();
return retval;
}
int
pwdb_update_aging(const char *username,
long min, long max, long warn, long inact, long lastchg)
{
const struct pwdb *_pwdb = NULL;
const struct pwdb_entry *_entry = NULL;
__pwdb_sptime sptime;
int retval, flags;
/* Now update the user entry */
retval = pwdb_start();
if (retval != PWDB_SUCCESS) {
return -1;
}
retval = pwdb_locate("user", PWDB_DEFAULT, username, PWDB_ID_UNKNOWN,
&_pwdb);
CHECK_ERROR(retval);
retval = pwdb_flags("user", _pwdb->source, &flags);
CHECK_ERROR(retval);
if (flags & PWDB_F_NOUPDATE) {
fprintf(stderr,
"%s: insufficient privilege to complete operation\n",
progname);
pwdb_delete(&_pwdb);
pwdb_end();
return -1;
}
if (min != -2) {
retval = pwdb_get_entry(_pwdb, "min_change", &_entry);
CHECK_ERROR(retval);
pwdb_entry_delete(&_entry);
sptime = min;
retval = pwdb_set_entry(_pwdb, "min_change",
&sptime, sizeof(sptime),
NULL, NULL, 0);
CHECK_ERROR(retval);
}
if (max != -2) {
retval = pwdb_get_entry(_pwdb, "max_change", &_entry);
CHECK_ERROR(retval);
pwdb_entry_delete(&_entry);
sptime = max;
retval = pwdb_set_entry(_pwdb, "max_change",
&sptime, sizeof(sptime),
NULL, NULL, 0);
CHECK_ERROR(retval);
}
if (warn != -2) {
retval = pwdb_get_entry(_pwdb, "warn_change", &_entry);
CHECK_ERROR(retval);
pwdb_entry_delete(&_entry);
sptime = warn;
retval = pwdb_set_entry(_pwdb, "warn_change",
&sptime, sizeof(sptime),
NULL, NULL, 0);
CHECK_ERROR(retval);
}
if (inact != -2) {
retval = pwdb_get_entry(_pwdb, "defer_change", &_entry);
CHECK_ERROR(retval);
pwdb_entry_delete(&_entry);
sptime = inact;
retval = pwdb_set_entry(_pwdb, "defer_change",
&sptime, sizeof(sptime),
NULL, NULL, 0);
CHECK_ERROR(retval);
}
retval = pwdb_replace("user", _pwdb->source, username,
PWDB_ID_UNKNOWN, &_pwdb);
CHECK_ERROR(retval);
retval = pwdb_delete(&_pwdb);
CHECK_ERROR(retval);
pwdb_end();
return retval;
}