|
Packit Service |
3e5a5a |
/*
|
|
Packit Service |
3e5a5a |
* Copyright Red Hat, Inc., 1998, 1999, 2001, 2002, 2015.
|
|
Packit Service |
3e5a5a |
*
|
|
Packit Service |
3e5a5a |
* Redistribution and use in source and binary forms, with or without
|
|
Packit Service |
3e5a5a |
* modification, are permitted provided that the following conditions
|
|
Packit Service |
3e5a5a |
* are met:
|
|
Packit Service |
3e5a5a |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit Service |
3e5a5a |
* notice, and the entire permission notice in its entirety,
|
|
Packit Service |
3e5a5a |
* including the disclaimer of warranties.
|
|
Packit Service |
3e5a5a |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit Service |
3e5a5a |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit Service |
3e5a5a |
* documentation and/or other materials provided with the distribution.
|
|
Packit Service |
3e5a5a |
* 3. The name of the author may not be used to endorse or promote
|
|
Packit Service |
3e5a5a |
* products derived from this software without specific prior
|
|
Packit Service |
3e5a5a |
* written permission.
|
|
Packit Service |
3e5a5a |
*
|
|
Packit Service |
3e5a5a |
* ALTERNATIVELY, this product may be distributed under the terms of
|
|
Packit Service |
3e5a5a |
* the GNU Public License, in which case the provisions of the GPL are
|
|
Packit Service |
3e5a5a |
* required INSTEAD OF the above restrictions. (This clause is
|
|
Packit Service |
3e5a5a |
* necessary due to a potential bad interaction between the GPL and
|
|
Packit Service |
3e5a5a |
* the restrictions contained in a BSD-style copyright.)
|
|
Packit Service |
3e5a5a |
*
|
|
Packit Service |
3e5a5a |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
Packit Service |
3e5a5a |
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
Packit Service |
3e5a5a |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
Packit Service |
3e5a5a |
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
Packit Service |
3e5a5a |
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
Packit Service |
3e5a5a |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
Packit Service |
3e5a5a |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit Service |
3e5a5a |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
Packit Service |
3e5a5a |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit Service |
3e5a5a |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
Packit Service |
3e5a5a |
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit Service |
3e5a5a |
*/
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Written by Cristian Gafton <gafton@redhat.com> */
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#include "config.h"
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#include <sys/types.h>
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#include <ctype.h>
|
|
Packit Service |
3e5a5a |
#include <pwd.h>
|
|
Packit Service |
3e5a5a |
#include <stdio.h>
|
|
Packit Service |
3e5a5a |
#include <stdlib.h>
|
|
Packit Service |
3e5a5a |
#include <string.h>
|
|
Packit Service |
3e5a5a |
#include <unistd.h>
|
|
Packit Service |
3e5a5a |
#include <popt.h>
|
|
Packit Service |
3e5a5a |
#include <errno.h>
|
|
Packit Service |
3e5a5a |
#include <limits.h>
|
|
Packit Service |
3e5a5a |
#include <syslog.h>
|
|
Packit Service |
3e5a5a |
#include <locale.h>
|
|
Packit Service |
3e5a5a |
#include <libintl.h>
|
|
Packit Service |
3e5a5a |
#include "pwdb.h"
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#ifdef WITH_SELINUX
|
|
Packit Service |
3e5a5a |
#include "selinux_utils.h"
|
|
Packit Service |
3e5a5a |
#else
|
|
Packit Service |
3e5a5a |
#define selinux_init(x) 0
|
|
Packit Service |
3e5a5a |
#define selinux_check_root() 0
|
|
Packit Service |
3e5a5a |
#endif
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#ifdef WITH_AUDIT
|
|
Packit Service |
3e5a5a |
#include <libaudit.h>
|
|
Packit Service |
3e5a5a |
#else
|
|
Packit Service |
3e5a5a |
#define audit_log_acct_message(d,ty,p,o,n,i,h,a,t,r) do { ; } while(0)
|
|
Packit Service |
3e5a5a |
static int audit_open(void) { errno = EPROTONOSUPPORT; return -1; }
|
|
Packit Service |
3e5a5a |
#endif
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#include <security/pam_appl.h>
|
|
Packit Service |
3e5a5a |
#include <security/pam_misc.h>
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
static int audit_fd = -1;
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* conversation function & corresponding structure */
|
|
Packit Service |
3e5a5a |
static struct pam_conv conv = {
|
|
Packit Service |
3e5a5a |
misc_conv,
|
|
Packit Service |
3e5a5a |
NULL
|
|
Packit Service |
3e5a5a |
};
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
const char *username = NULL; /* username specified on the command line */
|
|
Packit Service |
3e5a5a |
const char *progname = NULL; /* the name of the program */
|
|
Packit Service |
3e5a5a |
int passwd_flags = 0; /* flags specified by root */
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#define PASSWD_KEEP 0x0001 /* keep un-expired tokens */
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#define PASSWD_LOCK 0x0002 /* lock the password */
|
|
Packit Service |
3e5a5a |
#define PASSWD_UNLOCK 0x0004 /* unlock the password, if locked */
|
|
Packit Service |
3e5a5a |
#define PASSWD_DELETE 0x0008 /* delete the user's password */
|
|
Packit Service |
3e5a5a |
#define PASSWD_STATUS 0x0010 /* report the password status */
|
|
Packit Service |
3e5a5a |
#define PASSWD_FORCE 0x0020 /* force change of expired token */
|
|
Packit Service |
3e5a5a |
#define PASSWD_STDIN 0x0040 /* read the password from stdin (root only) */
|
|
Packit Service |
3e5a5a |
#define PASSWD_EXPIRE 0x0080 /* expire the password */
|
|
Packit Service |
3e5a5a |
#define PASSWD_ROOT 0x009E /* options which are mutually exclusive */
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#define PASSWD_MIN 0x0100 /* set the minimum password lifetime */
|
|
Packit Service |
3e5a5a |
#define PASSWD_MAX 0x0200 /* set the maximum password lifetime */
|
|
Packit Service |
3e5a5a |
#define PASSWD_WARN 0x0400 /* set the password warning */
|
|
Packit Service |
3e5a5a |
#define PASSWD_INACT 0x0800 /* set the inactive time */
|
|
Packit Service |
3e5a5a |
#define PASSWD_AGING 0x0F00 /* aging options */
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
#ifdef HAVE_PAM_FAIL_DELAY
|
|
Packit Service |
3e5a5a |
#define PASSWD_FAIL_DELAY 2000000 /* usec delay on failure */
|
|
Packit Service |
3e5a5a |
#endif
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* A conversation function which uses an internally-stored value for
|
|
Packit Service |
3e5a5a |
* the responses. */
|
|
Packit Service |
3e5a5a |
static int
|
|
Packit Service |
3e5a5a |
stdin_conv(int num_msg, const struct pam_message **msgm,
|
|
Packit Service |
3e5a5a |
struct pam_response **response, void *appdata_ptr)
|
|
Packit Service |
3e5a5a |
{
|
|
Packit Service |
3e5a5a |
struct pam_response *reply;
|
|
Packit Service |
3e5a5a |
int count;
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Sanity test. */
|
|
Packit Service |
3e5a5a |
if (num_msg <= 0) {
|
|
Packit Service |
3e5a5a |
return PAM_CONV_ERR;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Allocate memory for the responses. */
|
|
Packit Service |
3e5a5a |
reply = calloc(num_msg, sizeof(struct pam_response));
|
|
Packit Service |
3e5a5a |
if (reply == NULL) {
|
|
Packit Service |
3e5a5a |
return PAM_CONV_ERR;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Each prompt elicits the same response. */
|
|
Packit Service |
3e5a5a |
for (count = 0; count < num_msg; ++count) {
|
|
Packit Service |
3e5a5a |
if (msgm[count]->msg_style == PAM_PROMPT_ECHO_OFF) {
|
|
Packit Service |
3e5a5a |
reply[count].resp_retcode = 0;
|
|
Packit Service |
3e5a5a |
reply[count].resp = strdup(appdata_ptr);
|
|
Packit Service |
3e5a5a |
} else {
|
|
Packit Service |
3e5a5a |
reply[count].resp_retcode = 0;
|
|
Packit Service |
3e5a5a |
reply[count].resp = strdup("");
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Set the pointers in the response structure and return. */
|
|
Packit Service |
3e5a5a |
*response = reply;
|
|
Packit Service |
3e5a5a |
return PAM_SUCCESS;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Parse command-line arguments, rejecting conflicting flags and performing
|
|
Packit Service |
3e5a5a |
* various other initialization tasks. */
|
|
Packit Service |
3e5a5a |
static void
|
|
Packit Service |
3e5a5a |
parse_args(int argc, const char **argv,
|
|
Packit Service |
3e5a5a |
long *min, long *max, long *warn, long *inact)
|
|
Packit Service |
3e5a5a |
{
|
|
Packit Service |
3e5a5a |
poptContext optCon;
|
|
Packit Service |
3e5a5a |
int delete = 0, force = 0, keep = 0, lock = 0, status = 0, unlock = 0;
|
|
Packit Service |
3e5a5a |
int expire = 0;
|
|
Packit Service |
3e5a5a |
int use_stdin = 0;
|
|
Packit Service |
3e5a5a |
int rc;
|
|
Packit Service |
3e5a5a |
const char **extraArgs;
|
|
Packit Service |
3e5a5a |
struct poptOption options[] = {
|
|
Packit Service |
3e5a5a |
{"keep-tokens", 'k', POPT_ARG_NONE, &keep, 0,
|
|
Packit Service |
3e5a5a |
_("keep non-expired authentication tokens"), NULL},
|
|
Packit Service |
3e5a5a |
{"delete", 'd', POPT_ARG_NONE, &delete, 0,
|
|
Packit Service |
3e5a5a |
_("delete the password for the named account (root only); "
|
|
Packit Service |
3e5a5a |
"also removes password lock if any"), NULL},
|
|
Packit Service |
3e5a5a |
{"lock", 'l', POPT_ARG_NONE, &lock, 0,
|
|
Packit Service |
3e5a5a |
_("lock the password for the named account (root only)"),
|
|
Packit Service |
3e5a5a |
NULL},
|
|
Packit Service |
3e5a5a |
{"unlock", 'u', POPT_ARG_NONE, &unlock, 0,
|
|
Packit Service |
3e5a5a |
_("unlock the password for the named account (root only)"),
|
|
Packit Service |
3e5a5a |
NULL},
|
|
Packit Service |
3e5a5a |
{"expire", 'e', POPT_ARG_NONE, &expire, 0,
|
|
Packit Service |
3e5a5a |
_("expire the password for the named account (root only)"),
|
|
Packit Service |
3e5a5a |
NULL},
|
|
Packit Service |
3e5a5a |
{"force", 'f', POPT_ARG_NONE, &force, 0,
|
|
Packit Service |
3e5a5a |
_("force operation"), NULL},
|
|
Packit Service |
3e5a5a |
{"maximum", 'x', POPT_ARG_LONG, max, 0,
|
|
Packit Service |
3e5a5a |
_("maximum password lifetime (root only)"), "DAYS"},
|
|
Packit Service |
3e5a5a |
{"minimum", 'n', POPT_ARG_LONG, min, 0,
|
|
Packit Service |
3e5a5a |
_("minimum password lifetime (root only)"), "DAYS"},
|
|
Packit Service |
3e5a5a |
{"warning", 'w', POPT_ARG_LONG, warn, 0,
|
|
Packit Service |
3e5a5a |
_("number of days warning users receives before password "
|
|
Packit Service |
3e5a5a |
"expiration (root only)"), "DAYS"},
|
|
Packit Service |
3e5a5a |
{"inactive", 'i', POPT_ARG_LONG, inact, 0,
|
|
Packit Service |
3e5a5a |
_("number of days after password expiration when an account "
|
|
Packit Service |
3e5a5a |
"becomes disabled (root only)"), "DAYS"},
|
|
Packit Service |
3e5a5a |
{"status", 'S', POPT_ARG_NONE, &status, 0,
|
|
Packit Service |
3e5a5a |
_("report password status on the named account (root only)"),
|
|
Packit Service |
3e5a5a |
NULL},
|
|
Packit Service |
3e5a5a |
{"stdin", '\0', POPT_ARG_NONE, &use_stdin, 0,
|
|
Packit Service |
3e5a5a |
_("read new tokens from stdin (root only)"), NULL},
|
|
Packit Service |
3e5a5a |
POPT_AUTOHELP POPT_TABLEEND
|
|
Packit Service |
3e5a5a |
};
|
|
Packit Service |
3e5a5a |
struct passwd *pw;
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
*min = *max = *warn = *inact = -2;
|
|
Packit Service |
3e5a5a |
optCon = poptGetContext("passwd", argc, argv, options, 0);
|
|
Packit Service |
3e5a5a |
poptSetOtherOptionHelp(optCon, _("[OPTION...] <accountName>"));
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
if ((rc = poptGetNextOpt(optCon)) < -1) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr, _("%s: bad argument %s: %s\n"), progname,
|
|
Packit Service |
3e5a5a |
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
|
|
Packit Service |
3e5a5a |
poptStrerror(rc));
|
|
Packit Service |
3e5a5a |
exit(-3);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
extraArgs = poptGetArgs(optCon);
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
if (keep) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_KEEP;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (lock) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_LOCK;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (unlock) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_UNLOCK;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (expire) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_EXPIRE;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (status) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_STATUS;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (delete) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_DELETE;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (force) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_FORCE;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (use_stdin) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_STDIN;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (*min != -2) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_MIN;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (*max != -2) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_MAX;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (*warn != -2) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_WARN;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (*inact != -2) {
|
|
Packit Service |
3e5a5a |
passwd_flags |= PASSWD_INACT;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* The rest of the flags are mutually-exclusive, except for --force. */
|
|
Packit Service |
3e5a5a |
if (passwd_flags) {
|
|
Packit Service |
3e5a5a |
int tmp;
|
|
Packit Service |
3e5a5a |
int count;
|
|
Packit Service |
3e5a5a |
tmp = passwd_flags & PASSWD_ROOT;
|
|
Packit Service |
3e5a5a |
count = 0;
|
|
Packit Service |
3e5a5a |
/* Check the rightmost bit and shift right. */
|
|
Packit Service |
3e5a5a |
while (tmp != 0) {
|
|
Packit Service |
3e5a5a |
if (tmp & 0x01) {
|
|
Packit Service |
3e5a5a |
count++;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
tmp = tmp >> 1;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
/* Error if other bits are set. */
|
|
Packit Service |
3e5a5a |
if (count > 1) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: Only one of -l, -u, -d, -S may be specified.\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
exit(-2);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
/* Error out if we had -l/-u/-d/-S and an aging option. */
|
|
Packit Service |
3e5a5a |
if (count > 0) {
|
|
Packit Service |
3e5a5a |
tmp = passwd_flags & PASSWD_AGING;
|
|
Packit Service |
3e5a5a |
if (tmp != 0) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: Cannot mix one of -l, -u, -d, -S and one of -i, -n, -w, -x.\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
exit(-2);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* The only flag which unprivileged users get to use is -k. */
|
|
Packit Service |
3e5a5a |
if ((passwd_flags & ~PASSWD_KEEP) &&
|
|
Packit Service |
3e5a5a |
(getuid() != 0)) {
|
|
Packit Service |
3e5a5a |
/* Auditing is not needed for displaying status */
|
|
Packit Service |
3e5a5a |
if (passwd_flags != PASSWD_STATUS) {
|
|
Packit Service |
3e5a5a |
audit_log_acct_message(audit_fd, AUDIT_USER_CHAUTHTOK,
|
|
Packit Service |
3e5a5a |
NULL, "attempted-to-change-password-attribute",
|
|
Packit Service |
3e5a5a |
NULL, getuid(), NULL, NULL, NULL, 0);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
fprintf(stderr, _("Only root can do that.\n"));
|
|
Packit Service |
3e5a5a |
exit(-2);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Only root gets to specify a user name. */
|
|
Packit Service |
3e5a5a |
username = NULL;
|
|
Packit Service |
3e5a5a |
if ((extraArgs != NULL) && (extraArgs[0] != NULL)) {
|
|
Packit Service |
3e5a5a |
if (getuid() != 0) {
|
|
Packit Service |
3e5a5a |
/* The invoking user was not root. */
|
|
Packit Service |
3e5a5a |
audit_log_acct_message(audit_fd, AUDIT_USER_CHAUTHTOK,
|
|
Packit Service |
3e5a5a |
NULL, "attempted-to-change-password",
|
|
Packit Service |
3e5a5a |
extraArgs[0], getuid(), NULL, NULL, NULL, 0);
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: Only root can specify a user name.\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
exit(-3);
|
|
Packit Service |
3e5a5a |
} else {
|
|
Packit Service |
3e5a5a |
/* The invoking user was root. */
|
|
Packit Service |
3e5a5a |
username = extraArgs[0];
|
|
Packit Service |
3e5a5a |
/* Sanity-check the user name */
|
|
Packit Service |
3e5a5a |
if (strlen(username) > MAX_USERNAMESIZE) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: The user name supplied is too long.\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
exit(-3);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* If there is more than one unrecognized argument, we suddenly
|
|
Packit Service |
3e5a5a |
* get confused. */
|
|
Packit Service |
3e5a5a |
if (extraArgs[1] != NULL) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: Only one user name may be specified.\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
exit(-3);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Now if any of the -l, -u, -d, -S, -i, -n, -w, or -x options were
|
|
Packit Service |
3e5a5a |
* given, and a username was not specified, bail out. */
|
|
Packit Service |
3e5a5a |
if ((passwd_flags & ~PASSWD_KEEP) && (username == NULL)) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: This option requires a user name.\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
exit(-2);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Determine the name of the user whose account we're operating on,
|
|
Packit Service |
3e5a5a |
* and make sure the account exists. */
|
|
Packit Service |
3e5a5a |
if (username == NULL) {
|
|
Packit Service |
3e5a5a |
/* The invoking user. */
|
|
Packit Service |
3e5a5a |
pw = getpwuid(getuid());
|
|
Packit Service |
3e5a5a |
if (pw == NULL) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr, _("%s: Can not identify you!\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
exit(-3);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
username = strdup(pw->pw_name);
|
|
Packit Service |
3e5a5a |
} else {
|
|
Packit Service |
3e5a5a |
/* The name specified on the command-line. */
|
|
Packit Service |
3e5a5a |
pw = getpwnam(username);
|
|
Packit Service |
3e5a5a |
if (pw == NULL) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr, _("%s: Unknown user name '%s'.\n"),
|
|
Packit Service |
3e5a5a |
progname, username);
|
|
Packit Service |
3e5a5a |
exit(-4);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
int
|
|
Packit Service |
3e5a5a |
main(int argc, const char **argv)
|
|
Packit Service |
3e5a5a |
{
|
|
Packit Service |
3e5a5a |
int retval;
|
|
Packit Service |
3e5a5a |
long min, max, warn, inact;
|
|
Packit Service |
3e5a5a |
pam_handle_t *pamh = NULL;
|
|
Packit Service |
3e5a5a |
struct passwd *pwd;
|
|
Packit Service |
3e5a5a |
char *tty_name, *ttyn;
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
setlocale(LC_ALL, "");
|
|
Packit Service |
3e5a5a |
bindtextdomain("passwd", "/usr/share/locale");
|
|
Packit Service |
3e5a5a |
textdomain("passwd");
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
audit_fd = audit_open();
|
|
Packit Service |
3e5a5a |
if (audit_fd < 0 && !(errno == EINVAL || errno == EPROTONOSUPPORT ||
|
|
Packit Service |
3e5a5a |
errno == EAFNOSUPPORT)) {
|
|
Packit Service |
3e5a5a |
/* The above error codes are only given when the kernel doesn't
|
|
Packit Service |
3e5a5a |
* have audit compiled in. */
|
|
Packit Service |
3e5a5a |
fprintf(stderr, "Error - unable to connect to audit system\n");
|
|
Packit Service |
3e5a5a |
exit(1);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Parse command-line arguments. */
|
|
Packit Service |
3e5a5a |
progname = basename(argv[0]);
|
|
Packit Service |
3e5a5a |
parse_args(argc, argv, &min, &max, &warn, &inact);
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
pwd = getpwnam(username);
|
|
Packit Service |
3e5a5a |
if (pwd == NULL) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr, _("%s: Unknown user name '%s'.\n"),
|
|
Packit Service |
3e5a5a |
progname, username);
|
|
Packit Service |
3e5a5a |
exit(-4);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
if (audit_fd >= 0)
|
|
Packit Service |
3e5a5a |
selinux_init(audit_fd);
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
if (selinux_check_root() != 0) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr, _("%s: SELinux denying access due to security policy.\n"), progname);
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
audit_log_acct_message(audit_fd, AUDIT_USER_CHAUTHTOK,
|
|
Packit Service |
3e5a5a |
NULL, "attempted-to-change-password", NULL, pwd->pw_uid,
|
|
Packit Service |
3e5a5a |
NULL, NULL, NULL, 0);
|
|
Packit Service |
3e5a5a |
exit(1);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Handle account locking request. */
|
|
Packit Service |
3e5a5a |
if (passwd_flags & PASSWD_LOCK) {
|
|
Packit Service |
3e5a5a |
printf(_("Locking password for user %s.\n"), username);
|
|
Packit Service |
3e5a5a |
retval = pwdb_lock_password(username);
|
|
Packit Service |
3e5a5a |
printf("%s: %s\n", progname,
|
|
Packit Service |
3e5a5a |
retval ==
|
|
Packit Service |
3e5a5a |
0 ? _("Success") : _("Error (password not set?)"));
|
|
Packit Service |
3e5a5a |
audit_log_acct_message(audit_fd, AUDIT_ACCT_LOCK,
|
|
Packit Service |
3e5a5a |
NULL, "locked-password", NULL, pwd->pw_uid,
|
|
Packit Service |
3e5a5a |
NULL, NULL, NULL, retval == 0);
|
|
Packit Service |
3e5a5a |
return retval;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
/* Handle account unlocking request. */
|
|
Packit Service |
3e5a5a |
if (passwd_flags & PASSWD_UNLOCK) {
|
|
Packit Service |
3e5a5a |
printf(_("Unlocking password for user %s.\n"), username);
|
|
Packit Service |
3e5a5a |
retval = pwdb_unlock_password(username,
|
|
Packit Service |
3e5a5a |
passwd_flags & PASSWD_FORCE);
|
|
Packit Service |
3e5a5a |
printf("%s: %s\n", progname,
|
|
Packit Service |
3e5a5a |
retval == 0 ? _("Success") :
|
|
Packit Service |
3e5a5a |
retval ==
|
|
Packit Service |
3e5a5a |
-2 ? _("Unsafe operation (use -f to force)") :
|
|
Packit Service |
3e5a5a |
_("Error (password not set?)"));
|
|
Packit Service |
3e5a5a |
audit_log_acct_message(audit_fd, AUDIT_ACCT_UNLOCK,
|
|
Packit Service |
3e5a5a |
NULL, "unlocked-password", NULL, pwd->pw_uid,
|
|
Packit Service |
3e5a5a |
NULL, NULL, NULL, retval == 0);
|
|
Packit Service |
3e5a5a |
return retval;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
/* Handle password expiration request. */
|
|
Packit Service |
3e5a5a |
if (passwd_flags & PASSWD_EXPIRE) {
|
|
Packit Service |
3e5a5a |
printf(_("Expiring password for user %s.\n"), username);
|
|
Packit Service |
3e5a5a |
retval = pwdb_update_aging(username, -2, -2, -2, -2, 0);
|
|
Packit Service |
3e5a5a |
printf("%s: %s\n", progname,
|
|
Packit Service |
3e5a5a |
retval ==
|
|
Packit Service |
3e5a5a |
0 ? _("Success") : _("Error"));
|
|
Packit Service |
3e5a5a |
audit_log_acct_message(audit_fd, AUDIT_USER_MGMT,
|
|
Packit Service |
3e5a5a |
NULL, "expired-password", NULL, pwd->pw_uid,
|
|
Packit Service |
3e5a5a |
NULL, NULL, NULL, retval == 0);
|
|
Packit Service |
3e5a5a |
return retval;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
/* Handle password clearing request. */
|
|
Packit Service |
3e5a5a |
if (passwd_flags & PASSWD_DELETE) {
|
|
Packit Service |
3e5a5a |
printf(_("Removing password for user %s.\n"), username);
|
|
Packit Service |
3e5a5a |
retval = pwdb_clear_password(username);
|
|
Packit Service |
3e5a5a |
printf("%s: %s\n", progname,
|
|
Packit Service |
3e5a5a |
(retval == 0) ? _("Success") : _("Error"));
|
|
Packit Service |
3e5a5a |
audit_log_acct_message(audit_fd, AUDIT_USER_CHAUTHTOK,
|
|
Packit Service |
3e5a5a |
NULL, "deleted-password", NULL, pwd->pw_uid,
|
|
Packit Service |
3e5a5a |
NULL, NULL, NULL, retval == 0);
|
|
Packit Service |
3e5a5a |
return retval;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
/* Display account status. */
|
|
Packit Service |
3e5a5a |
if (passwd_flags & PASSWD_STATUS) {
|
|
Packit Service |
3e5a5a |
/* Auditing is not needed for displaying status */
|
|
Packit Service |
3e5a5a |
retval = pwdb_display_status(username);
|
|
Packit Service |
3e5a5a |
return retval;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
/* Adjust aging parameters. */
|
|
Packit Service |
3e5a5a |
if (passwd_flags & PASSWD_AGING) {
|
|
Packit Service |
3e5a5a |
char aubuf[PATH_MAX];
|
|
Packit Service |
3e5a5a |
printf(_("Adjusting aging data for user %s.\n"), username);
|
|
Packit Service |
3e5a5a |
retval = pwdb_update_aging(username, min, max, warn, inact, -2);
|
|
Packit Service |
3e5a5a |
printf("%s: %s\n", progname,
|
|
Packit Service |
3e5a5a |
(retval == 0) ? _("Success") : _("Error"));
|
|
Packit Service |
3e5a5a |
snprintf(aubuf, sizeof(aubuf), "changed-password-aging"
|
|
Packit Service |
3e5a5a |
" min=%li max=%li warn=%li inact=%li",
|
|
Packit Service |
3e5a5a |
min, max, warn, inact);
|
|
Packit Service |
3e5a5a |
audit_log_acct_message(audit_fd, AUDIT_USER_MGMT,
|
|
Packit Service |
3e5a5a |
NULL, aubuf, NULL, pwd->pw_uid,
|
|
Packit Service |
3e5a5a |
NULL, NULL, NULL, retval == 0);
|
|
Packit Service |
3e5a5a |
return retval;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* The standard behavior follows. At this point we know for whom
|
|
Packit Service |
3e5a5a |
* we are going to change a password, so let the invoking user
|
|
Packit Service |
3e5a5a |
* know what's going on. */
|
|
Packit Service |
3e5a5a |
printf(_("Changing password for user %s.\n"), username);
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* If we need to read the new password from stdin, read it and switch
|
|
Packit Service |
3e5a5a |
* to the really-quiet stdin conversation function. */
|
|
Packit Service |
3e5a5a |
if (passwd_flags & PASSWD_STDIN) {
|
|
Packit Service |
3e5a5a |
/* PAM's documentation says that PAM_MAX_RESP_SIZE is the
|
|
Packit Service |
3e5a5a |
* maximum supported length of the password, but in practice
|
|
Packit Service |
3e5a5a |
* the code (including examples in the OSF RFC) often truncates
|
|
Packit Service |
3e5a5a |
* data at PAM_MAX_RESP_SIZE - 1. So, refuse to use anything
|
|
Packit Service |
3e5a5a |
* longer than PAM_MAX_RESP_SIZE - 1, to prevent users from
|
|
Packit Service |
3e5a5a |
* setting a password they won't be able to use to log in. */
|
|
Packit Service |
3e5a5a |
char *ptr, newPassword[PAM_MAX_RESP_SIZE];
|
|
Packit Service |
3e5a5a |
int i;
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
i = read(STDIN_FILENO, newPassword,
|
|
Packit Service |
3e5a5a |
sizeof(newPassword));
|
|
Packit Service |
3e5a5a |
if (i < 0) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: error reading from stdin: %s\n"), progname,
|
|
Packit Service |
3e5a5a |
strerror(errno));
|
|
Packit Service |
3e5a5a |
exit(1);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
if (i == sizeof(newPassword)) {
|
|
Packit Service |
3e5a5a |
if (newPassword[i - 1] != '\n') {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: password too long, maximum is %zu"),
|
|
Packit Service |
3e5a5a |
progname, sizeof(newPassword) - 1);
|
|
Packit Service |
3e5a5a |
exit(1);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
i--;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
newPassword[i] = '\0';
|
|
Packit Service |
3e5a5a |
ptr = strchr(newPassword, '\n');
|
|
Packit Service |
3e5a5a |
if (ptr)
|
|
Packit Service |
3e5a5a |
*ptr = 0;
|
|
Packit Service |
3e5a5a |
conv.conv = stdin_conv;
|
|
Packit Service |
3e5a5a |
conv.appdata_ptr = strdup(newPassword);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Start up PAM. */
|
|
Packit Service |
3e5a5a |
retval = pam_start("passwd", username, &conv, &pamh);
|
|
Packit Service |
3e5a5a |
if (retval != PAM_SUCCESS) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: unable to start pam: %s\n"), progname,
|
|
Packit Service |
3e5a5a |
pam_strerror(pamh, retval));
|
|
Packit Service |
3e5a5a |
exit(1);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
if ((ttyn = ttyname(0)) != NULL) {
|
|
Packit Service |
3e5a5a |
if (strncmp(ttyn, "/dev/", 5) == 0)
|
|
Packit Service |
3e5a5a |
tty_name = ttyn+5;
|
|
Packit Service |
3e5a5a |
else
|
|
Packit Service |
3e5a5a |
tty_name = ttyn;
|
|
Packit Service |
3e5a5a |
retval = pam_set_item(pamh, PAM_TTY, tty_name);
|
|
Packit Service |
3e5a5a |
if (retval != PAM_SUCCESS) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr,
|
|
Packit Service |
3e5a5a |
_("%s: unable to set tty for pam: %s\n"), progname,
|
|
Packit Service |
3e5a5a |
pam_strerror(pamh, retval));
|
|
Packit Service |
3e5a5a |
pam_end(pamh, retval);
|
|
Packit Service |
3e5a5a |
exit(1);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
#ifdef HAVE_PAM_FAIL_DELAY
|
|
Packit Service |
3e5a5a |
/* We have to pause on failure, so tell libpam the minimum amount
|
|
Packit Service |
3e5a5a |
* of time it should wait after a failure. */
|
|
Packit Service |
3e5a5a |
retval = pam_fail_delay(pamh, PASSWD_FAIL_DELAY);
|
|
Packit Service |
3e5a5a |
if (retval != PAM_SUCCESS) {
|
|
Packit Service |
3e5a5a |
fprintf(stderr, _("%s: unable to set failure delay: %s\n"),
|
|
Packit Service |
3e5a5a |
progname, pam_strerror(pamh, retval));
|
|
Packit Service |
3e5a5a |
exit(1);
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
#endif
|
|
Packit Service |
3e5a5a |
|
|
Packit Service |
3e5a5a |
/* Go for it. Note: pam will send audit event. */
|
|
Packit Service |
3e5a5a |
retval = pam_chauthtok(pamh,
|
|
Packit Service |
3e5a5a |
(passwd_flags & PASSWD_KEEP) ?
|
|
Packit Service |
3e5a5a |
PAM_CHANGE_EXPIRED_AUTHTOK : 0);
|
|
Packit Service |
3e5a5a |
if (retval == PAM_SUCCESS) {
|
|
Packit Service |
3e5a5a |
/* We're done. Tell the invoking user that it worked. */
|
|
Packit Service |
3e5a5a |
retval = pam_end(pamh, PAM_SUCCESS);
|
|
Packit Service |
3e5a5a |
if (passwd_flags & PASSWD_KEEP)
|
|
Packit Service |
3e5a5a |
printf(_("%s: expired authentication tokens updated successfully.\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
else
|
|
Packit Service |
3e5a5a |
printf(_("%s: all authentication tokens updated successfully.\n"),
|
|
Packit Service |
3e5a5a |
progname);
|
|
Packit Service |
3e5a5a |
retval = 0;
|
|
Packit Service |
3e5a5a |
} else {
|
|
Packit Service |
3e5a5a |
/* Horrors! It failed. Relay the bad news. */
|
|
Packit Service |
3e5a5a |
fprintf(stderr, "%s: %s\n", progname,
|
|
Packit Service |
3e5a5a |
pam_strerror(pamh, retval));
|
|
Packit Service |
3e5a5a |
pam_end(pamh, retval);
|
|
Packit Service |
3e5a5a |
retval = 1;
|
|
Packit Service |
3e5a5a |
}
|
|
Packit Service |
3e5a5a |
return retval;
|
|
Packit Service |
3e5a5a |
}
|