a972c460fa
- icons - blank mode by default - BSD auth
2320 lines
56 KiB
C
2320 lines
56 KiB
C
#if !defined( lint ) && !defined( SABER )
|
|
static const char sccsid[] = "@(#)passwd.c 5.00 2000/11/01 xlockmore";
|
|
|
|
#endif
|
|
|
|
/*-
|
|
* passwd.c - passwd stuff.
|
|
*
|
|
* Copyright (c) 1988-91 by Patrick J. Naughton.
|
|
*
|
|
* Revision History:
|
|
*
|
|
* Changes maintained by David Bagley <bagleyd@tux.org>
|
|
* 23-Feb-2003: Timothy Reed <treed1@twcny.rr.com>
|
|
* Updated PAM_conv to call over to xlock to display messages
|
|
* and return responses to the calling PAM
|
|
* 01-Nov-2000: SIA passwording for Tru64 added
|
|
* 18-Feb-1999: allowroot option no longer ignored for PAM authentication.
|
|
* Sven Paas <Sven.Paas@t-online.de>
|
|
* 24-Jan-1998: Updated PAM support and made it configure-able.
|
|
* Marc Ewing <marc@redhat.com> Original PAM support from
|
|
* 25-Jul-96 Michael K. Johnson <johnsonm@redhat.com>
|
|
* 18-Jan-1998: Kerberos corrections by RLS <sinkr@cbl.umces.edu>
|
|
* 25-May-1996: When xlock is compiled with shadow passwords it will still
|
|
* work on non shadowed systems. Marek Michalkiewicz
|
|
* <marekm@i17linuxb.ists.pwr.wroc.pl>
|
|
* 25-Feb-1996: Lewis Muhlenkamp
|
|
* Added in ability for any of the root accounts to unlock
|
|
* screen. Message now gets sent to syslog if root does the
|
|
* unlocking.
|
|
* 23-Dec-1995: Ron Hitchens <ron@idiom.com> reorganized.
|
|
* 10-Dec-1995: More context handling stuff for DCE thanks to
|
|
* Terje Marthinussen <terjem@cc.uit.no>.
|
|
* 01-Sep-1995: DCE code added thanks to Heath A. Kehoe
|
|
* <hakehoe@icaen.uiowa.edu>.
|
|
* 24-Jun-1995: Extracted from xlock.c, encrypted passwords are now fetched
|
|
* on start-up to ensure correct operation (except Ultrix).
|
|
*/
|
|
|
|
#include "xlock.h"
|
|
#include "iostuff.h"
|
|
#include "passwd.h"
|
|
|
|
#ifdef VMS
|
|
#include <str$routines.h>
|
|
#include <starlet.h>
|
|
#define ROOT "SYSTEM"
|
|
#else
|
|
#define ROOT "root"
|
|
#endif
|
|
|
|
extern Bool allowroot;
|
|
extern Bool inroot;
|
|
extern Bool inwindow;
|
|
extern Bool grabmouse;
|
|
extern Bool nolock;
|
|
extern char *cpasswd;
|
|
|
|
#ifdef USE_PAM
|
|
#include <X11/Xlib.h>
|
|
#endif
|
|
|
|
#if defined(__CYGWIN__) || defined(SOLARIS2)
|
|
#include <crypt.h>
|
|
#endif
|
|
|
|
#if defined( USE_XLOCKRC ) || defined( FALLBACK_XLOCKRC )
|
|
#include <sys/stat.h> /* order of includes matters */
|
|
#endif
|
|
|
|
#if !defined( VMS ) && !defined( SUNOS_ADJUNCT_PASSWD )
|
|
#include <pwd.h>
|
|
#endif
|
|
|
|
#if defined( __bsdi__ ) && _BSDI_VERSION >= 199608 || defined(__OpenBSD__)
|
|
#define BSD_AUTH
|
|
#endif
|
|
|
|
#ifdef BSD_AUTH
|
|
#include <login_cap.h>
|
|
#include <bsd_auth.h>
|
|
#endif
|
|
|
|
#if ( HAVE_SYSLOG_H && defined( USE_SYSLOG ))
|
|
#include <syslog.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#ifndef errno
|
|
extern int errno;
|
|
#endif
|
|
|
|
#if ( HAVE_FCNTL_H && (defined( USE_MULTIPLE_ROOT ) || defined( USE_MULTIPLE_USER )))
|
|
#include <fcntl.h>
|
|
|
|
void get_multiple(struct passwd *);
|
|
void set_multiple(int uid);
|
|
|
|
#define BUFMAX 1024 /* Maximum size of pipe buffer */
|
|
|
|
|
|
/* Linked list to keep track of everyone that's authorized * to unlock the
|
|
screen. */
|
|
struct pwln {
|
|
char *pw_name;
|
|
#ifndef BSD_AUTH
|
|
char *pw_passwd;
|
|
#endif
|
|
struct pwln *next;
|
|
};
|
|
typedef struct pwln pwlnode;
|
|
typedef struct pwln *pwlptr;
|
|
|
|
pwlptr pwll, pwllh = (pwlptr) NULL;
|
|
extern pwlptr pwllh;
|
|
|
|
/* Function that creates and initializes a new node that * will be added to
|
|
the linked list. */
|
|
pwlptr
|
|
new_pwlnode(void)
|
|
{
|
|
pwlptr pwl;
|
|
|
|
if ((pwl = (pwlptr) malloc(sizeof (pwlnode))) == 0)
|
|
return ((pwlptr) ENOMEM);
|
|
|
|
pwl->pw_name = (char *) NULL;
|
|
#ifndef BSD_AUTH
|
|
pwl->pw_passwd = (char *) NULL;
|
|
#endif
|
|
pwl->next = (pwlptr) NULL;
|
|
|
|
return (pwl);
|
|
}
|
|
#endif
|
|
|
|
#ifdef ultrix
|
|
#include <auth.h>
|
|
|
|
#if defined( HAVE_SETEUID ) || defined(HAVE_SETREUID )
|
|
gid_t rgid, egid;
|
|
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef OSF1_ENH_SEC
|
|
#include <sys/security.h>
|
|
#include <prot.h>
|
|
#endif
|
|
|
|
#if defined( __linux__ ) && defined( __ELF__ ) && !defined( HAVE_SHADOW )
|
|
/*-
|
|
* Linux may or may not have shadow passwords, so it is best to make the same
|
|
* binary work with both shadow and non-shadow passwords. It's easy with the
|
|
* ELF libc since it has getspnam() and there is no need for any additional
|
|
* libraries like libshadow.a.
|
|
*/
|
|
#define HAVE_SHADOW
|
|
#endif
|
|
|
|
#if defined( __linux__ ) && defined( HAVE_SHADOW ) && defined( HAVE_PW_ENCRYPT )
|
|
/*-
|
|
* Deprecated - long passwords have known weaknesses. Also, pw_encrypt is
|
|
* non-standard (requires libshadow.a) while everything else you need to
|
|
* support shadow passwords is in the standard (ELF) libc.
|
|
*/
|
|
#define crypt pw_encrypt
|
|
#endif
|
|
|
|
#ifdef HAVE_SHADOW
|
|
#ifndef __hpux
|
|
#include <shadow.h>
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef SUNOS_ADJUNCT_PASSWD
|
|
#include <sys/label.h>
|
|
#include <sys/audit.h>
|
|
#include <pwdadj.h>
|
|
#define passwd passwd_adjunct
|
|
#define pw_passwd pwa_passwd
|
|
#define getpwnam(_s) getpwanam(_s)
|
|
#define pw_name pwa_name
|
|
#define getpwuid(_s) (((_s)==0)?getpwanam(ROOT):getpwanam(cuserid(NULL)))
|
|
#endif /* SUNOS_ADJUNCT_PASSWD */
|
|
|
|
/* System V Release 4 redefinitions of BSD functions and structures */
|
|
#if !defined( SHADOW ) && (defined( SYSV ) || defined( SVR4 ))
|
|
|
|
#ifdef LESS_THAN_AIX3_2
|
|
struct passwd {
|
|
char *pw_name;
|
|
char *pw_passwd;
|
|
uid_t pw_uid;
|
|
gid_t pw_gid;
|
|
char *pw_gecos;
|
|
char *pw_dir;
|
|
char *pw_shell;
|
|
};
|
|
|
|
#endif /* LESS_THAN_AIX3_2 */
|
|
|
|
#ifdef HPUX_SECURE_PASSWD
|
|
#include <hpsecurity.h>
|
|
#include <prot.h>
|
|
#define crypt bigcrypt
|
|
|
|
/* #define seteuid(_eu) setresuid(-1, _eu, -1) */
|
|
#define passwd s_passwd
|
|
#define getpwnam(_s) getspwnam(_s)
|
|
#define getpwuid(_u) getspwuid(_u)
|
|
#endif /* HPUX_SECURE_PASSWD */
|
|
|
|
#endif /* defined( SYSV ) || defined( SVR4 ) */
|
|
|
|
#ifdef VMS
|
|
#include <uaidef.h>
|
|
#define VMS_PASSLENGTH 9
|
|
static short uai_salt, root_salt;
|
|
static char hash_password[VMS_PASSLENGTH], hash_system[VMS_PASSLENGTH];
|
|
static char root_password[VMS_PASSLENGTH], root_system[VMS_PASSLENGTH];
|
|
static char uai_encrypt, root_encrypt;
|
|
|
|
struct ascid {
|
|
short len;
|
|
char dtype;
|
|
char c_class;
|
|
char *addr;
|
|
};
|
|
|
|
static struct ascid username, rootuser;
|
|
|
|
struct itmlst {
|
|
short buflen;
|
|
short code;
|
|
long addr;
|
|
long retadr;
|
|
};
|
|
|
|
#endif /* VMS */
|
|
|
|
#ifdef HP_PASSWDETC /* HAVE_SYS_WAIT_H */
|
|
#include <sys/wait.h>
|
|
|
|
/*-
|
|
* Potential security problem on HP with PasswdEtc
|
|
* This hack is totally crazy and has security holes.
|
|
*/
|
|
|
|
#if 1
|
|
/* Change 1 to 0 */
|
|
Hackers can probably get at the encrypted passwd file
|
|
#endif
|
|
|
|
#endif /* HP_PASSWDETC */
|
|
|
|
#ifdef AFS
|
|
#include <afs/kauth.h>
|
|
#include <afs/kautils.h>
|
|
#endif /* AFS */
|
|
|
|
#ifdef SIA
|
|
#include<sia.h>
|
|
#include<siad.h>
|
|
#endif /* SIA */
|
|
|
|
char user[PASSLENGTH];
|
|
#ifdef GLOBAL_UNLOCK
|
|
char global_user[PASSLENGTH];
|
|
#endif
|
|
|
|
#ifdef USE_PAM
|
|
|
|
/* used to pass the password to the conversation function */
|
|
static char *PAM_password;
|
|
|
|
/*-
|
|
* PAM conversation function
|
|
* Here we assume (for now, at least) that echo on means login name, and
|
|
* echo off means password.
|
|
*/
|
|
|
|
int
|
|
PAM_conv(int num_msg,
|
|
#ifndef SOLARIS2
|
|
const
|
|
#endif
|
|
struct pam_message **msg,
|
|
struct pam_response **resp,
|
|
void *appdata_ptr)
|
|
{
|
|
int replies = 0;
|
|
struct pam_response *reply = NULL;
|
|
|
|
|
|
#define COPY_STRING(s) (s) ? strdup(s) : NULL
|
|
|
|
reply = (struct pam_response *) malloc(sizeof (struct pam_response) *
|
|
num_msg);
|
|
|
|
// reply[] members is not initialized!
|
|
// As a result - abort trap when PAM tries to free reply structure
|
|
// after PAM_ERROR_MSG processing.
|
|
|
|
// So I just initialize reply here with default values and drop
|
|
// initialization from code below (if code matches).
|
|
|
|
reply[replies].resp_retcode = PAM_SUCCESS; // be optimistic
|
|
reply[replies].resp = NULL;
|
|
|
|
if (!reply)
|
|
return PAM_CONV_ERR;
|
|
|
|
for (replies = 0; replies < num_msg; replies++) {
|
|
#ifdef DEBUG
|
|
(void) printf( "PAM_conv: message of style (%d) received\n", msg[replies]->msg_style );
|
|
(void) printf( " + Message is: (%s)\n", msg[replies]->msg );
|
|
#endif
|
|
switch (msg[replies]->msg_style) {
|
|
case PAM_PROMPT_ECHO_ON:
|
|
#ifdef DEBUG
|
|
(void) printf( " + Message style: PAM_PROMPT_ECHO_ON\n" );
|
|
#endif
|
|
PAM_putText( msg[replies], &reply[replies], True );
|
|
/* PAM frees resp */
|
|
break;
|
|
case PAM_PROMPT_ECHO_OFF:
|
|
#ifdef DEBUG
|
|
(void) printf( " + Message style: PAM_PROMPT_ECHO_OFF\n" );
|
|
#endif
|
|
if( strstr( msg[replies]->msg, "Password" ) == NULL ) {
|
|
PAM_putText( msg[replies], &reply[replies], False );
|
|
} else {
|
|
reply[replies].resp = COPY_STRING(PAM_password);
|
|
}
|
|
/* PAM frees resp */
|
|
break;
|
|
case PAM_TEXT_INFO:
|
|
#ifdef DEBUG
|
|
(void) printf( " + Message style: PAM_TEXT_INFO\n" );
|
|
#endif
|
|
if( strstr( msg[replies]->msg, "Password" ) == NULL ) {
|
|
PAM_putText( msg[replies], &reply[replies], False );
|
|
}
|
|
/* PAM frees resp */
|
|
break;
|
|
case PAM_ERROR_MSG:
|
|
#ifdef DEBUG
|
|
(void) printf( " + Message style: PAM_ERROR_MSG\n" );
|
|
#endif
|
|
if( strstr( msg[replies]->msg, "Password" ) == NULL ) {
|
|
PAM_putText( msg[replies], &reply[replies], False );
|
|
}
|
|
/* PAM frees resp */
|
|
break;
|
|
default:
|
|
/* Must be an error of some sort... */
|
|
#ifdef DEBUG
|
|
(void) printf( " + Message style: unknown\n" );
|
|
#endif
|
|
free(reply);
|
|
return PAM_CONV_ERR;
|
|
}
|
|
#ifdef DEBUG
|
|
(void) printf( " + Response is: (%s). Return Code is: (%d)\n",
|
|
reply[replies].resp, reply[replies].resp_retcode );
|
|
#endif
|
|
}
|
|
*resp = reply;
|
|
return PAM_SUCCESS;
|
|
}
|
|
|
|
static const struct pam_conv PAM_conversation =
|
|
{
|
|
PAM_conv,
|
|
NULL
|
|
};
|
|
|
|
#endif /* USE_PAM */
|
|
|
|
#if !defined( ultrix ) && !defined( USE_PAM )
|
|
static char userpass[PASSLENGTH];
|
|
static char rootpass[PASSLENGTH];
|
|
#ifdef USE_XLOCK_GROUP
|
|
#include <grp.h>
|
|
static char *grouppass = (char *) NULL;
|
|
static void getCryptedXlockGroupPasswds();
|
|
static int checkGroupXlockPasswds(char *buffer);
|
|
#endif
|
|
|
|
#ifdef VMS
|
|
static char root[] = ROOT;
|
|
|
|
#endif
|
|
#endif /* !ultrix && !USE_PAM */
|
|
|
|
#ifdef DCE_PASSWD
|
|
static int usernet, rootnet;
|
|
static int check_dce_net_passwd(char *, char *);
|
|
|
|
#endif
|
|
|
|
#if defined( HAVE_KRB4 ) || defined( HAVE_KRB5 )
|
|
#ifdef HAVE_KRB4
|
|
#include <krb.h>
|
|
static int krb_check_password(struct passwd *, char *);
|
|
#else /* HAVE_KRB5 */
|
|
#include <krb5.h>
|
|
#include <com_err.h>
|
|
int krb5_valid = 0;
|
|
extern Display *dsp;
|
|
extern Window parent;
|
|
extern Bool parentSet;
|
|
static int krb_check_password(char *, char *);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|
#ifdef SunCplusplus
|
|
#include <crypt.h>
|
|
#else
|
|
#if 0
|
|
#if 1
|
|
extern char *crypt(char *, char *);
|
|
|
|
#else
|
|
extern char *crypt(const char *, const char *);
|
|
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef PASSWD_HELPER_PROGRAM
|
|
static int run_helper(const char *user, const char *pass);
|
|
#endif
|
|
|
|
#if (defined( USE_XLOCKRC ) || (!defined( OSF1_ENH_SEC ) && !defined( HP_PASSWDETC ) && !defined( VMS )))
|
|
static struct passwd *
|
|
my_passwd_entry(void)
|
|
{
|
|
int uid;
|
|
struct passwd *pw;
|
|
|
|
#ifdef HAVE_SHADOW
|
|
struct spwd *spw;
|
|
|
|
#endif
|
|
|
|
uid = (int) getuid();
|
|
#ifndef SUNOS_ADJUNCT_PASSWD
|
|
{
|
|
char *logname;
|
|
|
|
pw = 0;
|
|
logname = getenv("LOGNAME");
|
|
if (logname == NULL)
|
|
logname = getenv("USER");
|
|
if (logname != NULL) {
|
|
pw = getpwnam(logname);
|
|
if (pw && ((int) pw->pw_uid != uid))
|
|
pw = 0;
|
|
}
|
|
}
|
|
if (!pw)
|
|
#endif
|
|
pw = getpwuid(uid);
|
|
if (!pw)
|
|
return (pw);
|
|
#ifdef HAVE_SHADOW
|
|
/*-
|
|
* PURIFY on Solaris 2 reports a 1024 byte memory leak on the following line
|
|
* if using NIS compatibility mode, and is internal to libc.so */
|
|
if ((spw = getspnam(pw->pw_name)) != NULL) {
|
|
char *tmp; /* swap */
|
|
|
|
tmp = pw->pw_passwd;
|
|
pw->pw_passwd = spw->sp_pwdp;
|
|
spw->sp_pwdp = tmp;
|
|
}
|
|
endspent();
|
|
#endif
|
|
return (pw);
|
|
}
|
|
#endif
|
|
|
|
#ifdef SAFEWORD
|
|
int
|
|
checkDynamic()
|
|
{
|
|
struct passwd *pw;
|
|
char *buf;
|
|
|
|
#ifndef SAFELOG_SWCHECK
|
|
#define SAFELOG_SWCHECK "/progs/safelog/swcheck"
|
|
#endif
|
|
#ifndef SAFELOG_IDENT
|
|
#define SAFELOG_IDENT "/progs/safelog/ident"
|
|
#endif
|
|
|
|
|
|
if (!(pw = my_passwd_entry())) {
|
|
/*if ((pw = (struct passwd *) getpwuid(getuid())) == NULL) */
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user shell.\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
return (!(strcmp(pw->pw_shell, SAFELOG_SWCHECK) &&
|
|
strcmp(pw->pw_shell, SAFELOG_IDENT)));
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
getUserName(void)
|
|
{
|
|
|
|
#ifdef VMS
|
|
(void) strcpy(user, cuserid(NULL));
|
|
#else /* !VMS */
|
|
#ifdef HP_PASSWDETC
|
|
|
|
/*-
|
|
* The PasswdEtc libraries have replacement passwd functions that make
|
|
* queries to DomainOS registries. Unfortunately, these functions do
|
|
* wierd things to the process (at minimum, signal handlers get changed,
|
|
* there are probably other things as well) that cause xlock to become
|
|
* unstable.
|
|
*
|
|
* As a (really, really sick) workaround, we'll fork() and do the getpw*()
|
|
* calls in the child, and pass the information back through a pipe.
|
|
*/
|
|
struct passwd *pw;
|
|
int pipefd[2], n, total = 0, stat_loc;
|
|
pid_t pid;
|
|
char *buf;
|
|
|
|
pipe(pipefd);
|
|
|
|
if ((pid = fork()) == 0) {
|
|
(void) close(pipefd[0]);
|
|
pw = getpwuid(getuid());
|
|
write(pipefd[1], pw->pw_name, strlen(pw->pw_name));
|
|
(void) close(pipefd[1]);
|
|
_exit(0);
|
|
}
|
|
if (pid < 0) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user password (fork failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
(void) close(pipefd[1]);
|
|
|
|
while ((n = read(pipefd[0], &(user[total]), 50)) > 0)
|
|
total += n;
|
|
|
|
wait(&stat_loc);
|
|
|
|
if (n < 0) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user name (read failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
user[total] = 0;
|
|
|
|
if (total < 1) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user name (lookups failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
#else /* !HP_PASSWDETC */
|
|
#ifdef OSF1_ENH_SEC
|
|
struct pr_passwd *pw;
|
|
char *buf;
|
|
|
|
/*if ((pw = getprpwuid(getuid())) == NULL) */
|
|
if ((pw = getprpwuid(starting_ruid())) == NULL) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user name.\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
(void) strcpy(user, pw->ufld.fd_name);
|
|
#else /* !OSF1_ENH_SEC */
|
|
|
|
struct passwd *pw;
|
|
char *buf;
|
|
|
|
#ifdef HAVE_KRB5
|
|
krb5_context context;
|
|
krb5_principal me = NULL;
|
|
krb5_ccache cc = NULL;
|
|
krb5_error_code code;
|
|
char *krb5_user = NULL;
|
|
int got_context = 0;
|
|
|
|
krb5_valid = 0;
|
|
|
|
code = krb5_init_context(&context);
|
|
|
|
if (code == 0) {
|
|
got_context = 1;
|
|
code = krb5_cc_default(context, &cc);
|
|
}
|
|
|
|
if (code == 0)
|
|
code = krb5_cc_get_principal(context, cc, &me);
|
|
|
|
if (code == 0)
|
|
code = krb5_unparse_name(context, me, &krb5_user);
|
|
|
|
if (cc)
|
|
krb5_cc_close(context, cc);
|
|
|
|
if (me)
|
|
krb5_free_principal(context, me);
|
|
|
|
if (got_context)
|
|
krb5_free_context(context);
|
|
|
|
if (code == 0) {
|
|
if (strlen(krb5_user) < PASSLENGTH + 1) {
|
|
strncpy(user, krb5_user, PASSLENGTH);
|
|
krb5_valid = 1;
|
|
} else
|
|
code = 255;
|
|
|
|
free(krb5_user);
|
|
}
|
|
|
|
if (code) {
|
|
|
|
#endif /* HAVE_KRB5 */
|
|
if (!(pw = my_passwd_entry())) {
|
|
/*if ((pw = (struct passwd *) getpwuid(getuid())) == NULL) */
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user name.\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
(void) strcpy(user, pw->pw_name);
|
|
|
|
#ifdef HAVE_KRB5
|
|
}
|
|
#endif /* HAVE_KRB5 */
|
|
|
|
#if ( HAVE_FCNTL_H && (defined( USE_MULTIPLE_ROOT ) || defined( USE_MULTIPLE_USER )))
|
|
get_multiple(pw);
|
|
#endif
|
|
|
|
#endif /* !OSF1_ENH_SEC */
|
|
#endif /* !HP_PASSWDETC */
|
|
#endif /* !VMS */
|
|
}
|
|
|
|
#if defined( USE_XLOCKRC ) || defined( FALLBACK_XLOCKRC )
|
|
|
|
#define CPASSLENGTH 14
|
|
#define CPASSCHARS 64
|
|
static void
|
|
gpasskey(char *pass)
|
|
{
|
|
static char saltchars[CPASSCHARS + 1] =
|
|
"abcdefghijklmnopwrstuvwxyzABCDEFGHIJKLMNOPWRSTUVWXYZ1234567890./";
|
|
char *pw, *pw2, salt[3];
|
|
#if 0
|
|
char *getpass(const char *);
|
|
#endif
|
|
|
|
pw = (char *) getpass(" Key: ");
|
|
pw2 = (char *) getpass("Again: ");
|
|
if (strncmp(pw, pw2, 8) != 0) {
|
|
(void) fprintf(stderr, "%s: Mismatch, try again\n", ProgramName);
|
|
exit(1);
|
|
}
|
|
/* grab a random printable character that is not a colon */
|
|
salt[0] = saltchars[LRAND() & (CPASSCHARS - 1)];
|
|
salt[1] = saltchars[LRAND() & (CPASSCHARS - 1)];
|
|
salt[2] = '\0';
|
|
(void) strncpy(pass, (char *) crypt(pw, salt), CPASSLENGTH);
|
|
}
|
|
|
|
static void
|
|
gpass(void)
|
|
{
|
|
FILE *fp;
|
|
char xlockrc[MAXPATHLEN], *home;
|
|
|
|
if (!cpasswd || !*cpasswd) {
|
|
/*
|
|
* No password given on command line or from database, get from
|
|
* $HOME/.xlockrc instead.
|
|
*/
|
|
if ((home = getenv("HOME")) == 0) {
|
|
/* struct passwd *p = getpwuid(getuid()); */
|
|
struct passwd *p = my_passwd_entry();
|
|
|
|
if (p == 0) {
|
|
char *buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
|
|
(void) sprintf(buf,
|
|
"%s: Who are you?\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
home = p->pw_dir;
|
|
}
|
|
(void) strncpy(xlockrc, home, MAXPATHLEN);
|
|
(void) strncat(xlockrc, "/.xlockrc", MAXPATHLEN);
|
|
if ((fp = my_fopen(xlockrc, "r")) == NULL) {
|
|
if ((fp = my_fopen(xlockrc, "w")) != NULL)
|
|
(void) fchmod(fileno(fp), 0600);
|
|
#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
|
|
(void) strcpy(userpass, "*");
|
|
#else
|
|
gpasskey(userpass);
|
|
#endif /* KRB4 || KRB5 */
|
|
if (fp)
|
|
(void) fprintf(fp, "%s\n", userpass);
|
|
} else {
|
|
char buf[BUFSIZ];
|
|
|
|
(void) fchmod(fileno(fp), 0600);
|
|
buf[0] = '\0';
|
|
if ((fgets(buf, sizeof buf, fp) == NULL) ||
|
|
(!(strlen(buf) == CPASSLENGTH - 1 ||
|
|
#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
|
|
(((strlen(buf) == 1) || strlen(buf) == 2)
|
|
&& buf[0] == '*') ||
|
|
#endif
|
|
(strlen(buf) == CPASSLENGTH && buf[CPASSLENGTH - 1] == '\n')))) {
|
|
(void) fprintf(stderr, "%s: %s crypted password %s\n", xlockrc,
|
|
buf[0] == '\0' ? "null" : "bad", buf);
|
|
#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
|
|
gpasskey(buf);
|
|
#else
|
|
exit(1);
|
|
#endif
|
|
}
|
|
buf[CPASSLENGTH - 1] = '\0';
|
|
(void) strncpy(userpass, buf, CPASSLENGTH);
|
|
}
|
|
if (fp)
|
|
(void) fclose(fp);
|
|
} else {
|
|
|
|
if (strlen(cpasswd) != CPASSLENGTH - 1) {
|
|
(void) fprintf(stderr, "%s: bad crypted password %s\n",
|
|
ProgramName, cpasswd);
|
|
exit(1);
|
|
} else
|
|
(void) strncpy(userpass, cpasswd, CPASSLENGTH);
|
|
}
|
|
}
|
|
|
|
#endif /* USE_XLOCKRC || FALLBACK_XLOCKRC */
|
|
|
|
#if !defined( ultrix ) && !defined( DCE_PASSWD ) && !defined( BSD_AUTH ) && !defined ( USE_PAM )
|
|
#ifndef USE_XLOCKRC
|
|
|
|
#if defined( HAVE_SHADOW ) && !defined( AFS ) && !defined( SIA )
|
|
static int
|
|
passwd_invalid(char *passwd)
|
|
{
|
|
int i = strlen(passwd);
|
|
|
|
return (i == 1 || i == 2);
|
|
}
|
|
|
|
extern Bool verbose, debug;
|
|
#endif
|
|
|
|
#ifdef OSF1_ENH_SEC
|
|
static int user_oldcrypt, root_oldcrypt;
|
|
#endif
|
|
|
|
static void
|
|
getCryptedUserPasswd(void)
|
|
{
|
|
#ifdef VMS
|
|
struct itmlst il[4];
|
|
|
|
il[0].buflen = 2;
|
|
il[0].code = UAI$_SALT;
|
|
il[0].addr = (long) &uai_salt;
|
|
il[0].retadr = 0;
|
|
il[1].buflen = 8;
|
|
il[1].code = UAI$_PWD;
|
|
il[1].addr = (long) &hash_password;
|
|
il[1].retadr = 0;
|
|
il[2].buflen = 1;
|
|
il[2].code = UAI$_ENCRYPT;
|
|
il[2].addr = (long) &uai_encrypt;
|
|
il[2].retadr = 0;
|
|
il[3].buflen = 0;
|
|
il[3].code = 0;
|
|
il[3].addr = 0;
|
|
il[3].retadr = 0;
|
|
|
|
username.len = strlen(user);
|
|
username.dtype = 0;
|
|
username.c_class = 0;
|
|
username.addr = user;
|
|
|
|
sys$getuai(0, 0, &username, &il, 0, 0, 0);
|
|
#else /* !VMS */
|
|
#ifdef HP_PASSWDETC
|
|
|
|
/*-
|
|
* still very sick, see above
|
|
*/
|
|
struct passwd *pw;
|
|
int pipefd[2], n, total = 0, stat_loc;
|
|
pid_t pid;
|
|
char *buf;
|
|
|
|
pipe(pipefd);
|
|
|
|
if ((pid = fork()) == 0) {
|
|
(void) close(pipefd[0]);
|
|
pw = getpwuid(getuid());
|
|
write(pipefd[1], pw->pw_passwd, strlen(pw->pw_passwd));
|
|
(void) close(pipefd[1]);
|
|
_exit(0);
|
|
}
|
|
if (pid < 0) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user password (fork failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
(void) close(pipefd[1]);
|
|
|
|
while ((n = read(pipefd[0], &(userpass[total]), 50)) > 0)
|
|
total += n;
|
|
|
|
wait(&stat_loc);
|
|
|
|
if (n < 0) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user password (read failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
user[total] = 0;
|
|
|
|
if (total < 1) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user password (lookups failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
#else /* !HP_PASSWDETC */
|
|
#ifdef OSF1_ENH_SEC
|
|
struct pr_passwd *pw;
|
|
char *buf;
|
|
|
|
/*if ((pw = getprpwuid(getuid())) == NULL) */
|
|
if ((pw = getprpwuid(starting_ruid())) == NULL) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get encrypted user password.\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
(void) strcpy(userpass, pw->ufld.fd_encrypt);
|
|
/* also save encryption algorithm associated with encrypted password */
|
|
user_oldcrypt = pw->ufld.fd_oldcrypt;
|
|
#else /* !OSF1_ENH_SEC */
|
|
|
|
struct passwd *pw;
|
|
char *buf;
|
|
|
|
if (!(pw = my_passwd_entry())) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get encrypted user password.\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
/*if ((pw = (struct passwd *) getpwuid(getuid())) == NULL) */
|
|
/* Check if there is any chance of unlocking the display later... */
|
|
/* Program probably needs to be setuid to root. */
|
|
(void) strcpy(userpass, pw->pw_passwd);
|
|
#ifdef HAVE_SHADOW
|
|
#if !defined ( AFS ) && !defined ( SIA )
|
|
if (passwd_invalid(pw->pw_passwd)) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
if (verbose || debug) {
|
|
(void) fprintf(stderr,
|
|
"%s: it looks like you have shadow passwording.\n",
|
|
ProgramName);
|
|
(void) fprintf(stderr, "Contact your administrator to setgid or\n");
|
|
(void) fprintf(stderr, "setuid %s for /etc/shadow read access.\n",
|
|
ProgramName);
|
|
#ifdef FALLBACK_XLOCKRC
|
|
(void) fprintf(stderr, "Falling back on $HOME/.xlockrc password.\n");
|
|
#endif
|
|
}
|
|
#ifdef FALLBACK_XLOCKRC
|
|
gpass();
|
|
#endif
|
|
}
|
|
#endif /* !AFS && !SIA */
|
|
#endif /* HAVE_SHADOW */
|
|
#if ( HAVE_FCNTL_H && defined( USE_MULTIPLE_USER ))
|
|
set_multiple(getuid());
|
|
#endif /* HAVE_FCNTL_H && MULTIPLE_USER */
|
|
#endif /* !OSF1_ENH_SEC */
|
|
#endif /* !HP_PASSWDETC */
|
|
#endif /* !VMS */
|
|
}
|
|
|
|
#endif /* !USE_XLOCKRC */
|
|
|
|
static void
|
|
getCryptedRootPasswd(void)
|
|
{
|
|
|
|
#ifdef VMS
|
|
struct itmlst il[4];
|
|
|
|
il[0].buflen = 2;
|
|
il[0].code = UAI$_SALT;
|
|
il[0].addr = (long) &root_salt;
|
|
il[0].retadr = 0;
|
|
il[1].buflen = 8;
|
|
il[1].code = UAI$_PWD;
|
|
il[1].addr = (long) &root_password;
|
|
il[1].retadr = 0;
|
|
il[2].buflen = 1;
|
|
il[2].code = UAI$_ENCRYPT;
|
|
il[2].addr = (long) &root_encrypt;
|
|
il[2].retadr = 0;
|
|
il[3].buflen = 0;
|
|
il[3].code = 0;
|
|
il[3].addr = 0;
|
|
il[3].retadr = 0;
|
|
|
|
rootuser.len = strlen(root);
|
|
rootuser.dtype = 0;
|
|
rootuser.c_class = 0;
|
|
rootuser.addr = root;
|
|
|
|
sys$getuai(0, 0, &rootuser, &il, 0, 0, 0);
|
|
#else /* !VMS */
|
|
#ifdef HP_PASSWDETC
|
|
|
|
/*-
|
|
* Still really, really sick. See above.
|
|
*/
|
|
struct passwd *pw;
|
|
int pipefd[2], n, total = 0, stat_loc;
|
|
pid_t pid;
|
|
char *buf;
|
|
|
|
pipe(pipefd);
|
|
|
|
if ((pid = fork()) == 0) {
|
|
(void) close(pipefd[0]);
|
|
pw = getpwnam(ROOT);
|
|
write(pipefd[1], pw->pw_passwd, strlen(pw->pw_passwd));
|
|
(void) close(pipefd[1]);
|
|
_exit(0);
|
|
}
|
|
if (pid < 0) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get root password (fork failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
(void) close(pipefd[1]);
|
|
|
|
while ((n = read(pipefd[0], &(rootpass[total]), 50)) > 0)
|
|
total += n;
|
|
|
|
wait(&stat_loc);
|
|
|
|
if (n < 0) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get root password (read failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
rootpass[total] = 0;
|
|
|
|
if (total < 1) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get root password (lookups failed)\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
#else /* !HP_PASSWDETC */
|
|
#ifdef OSF1_ENH_SEC
|
|
struct pr_passwd *pw;
|
|
char *buf;
|
|
|
|
if ((pw = getprpwnam(ROOT)) == NULL) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get encrypted root password.\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
(void) strcpy(rootpass, pw->ufld.fd_encrypt);
|
|
/* also save encryption algorithm associated with encrypted password */
|
|
root_oldcrypt = pw->ufld.fd_oldcrypt;
|
|
#else /* !OSF1_ENH_SEC */
|
|
struct passwd *pw;
|
|
char *buf;
|
|
|
|
#ifdef HAVE_SHADOW
|
|
struct spwd *spw;
|
|
|
|
#endif
|
|
|
|
if (!(pw = getpwnam(ROOT)))
|
|
if (!(pw = getpwuid(0))) {
|
|
/*if ((pw = (struct passwd *) getpwuid(0)) == NULL) */
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get encrypted root password.\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
#ifdef HAVE_SHADOW
|
|
/*-
|
|
* PURIFY on Solaris 2 reports a 1024 byte memory leak on the following line
|
|
* if using NIS compatibility mode, and is internal to libc.so */
|
|
if ((spw = getspnam(pw->pw_name)) != NULL) {
|
|
char *tmp; /* swap */
|
|
|
|
tmp = pw->pw_passwd;
|
|
pw->pw_passwd = spw->sp_pwdp;
|
|
spw->sp_pwdp = tmp;
|
|
}
|
|
endspent();
|
|
#endif
|
|
(void) strcpy(rootpass, pw->pw_passwd);
|
|
|
|
#if ( HAVE_FCNTL_H && defined( USE_MULTIPLE_ROOT ))
|
|
set_multiple(0);
|
|
#endif /* HAVE_FCNTL_H && MULTIPLE_ROOT */
|
|
|
|
#endif /* !OSF1_ENH_SEC */
|
|
#endif /* !HP_PASSWDETC */
|
|
#endif /* !VMS */
|
|
}
|
|
|
|
#endif /* !ultrix && !DCE_PASSWD && !BSD_AUTH && !USE_PAM */
|
|
|
|
|
|
#ifdef GLOBAL_UNLOCK
|
|
void
|
|
checkUser(char *buffer)
|
|
{
|
|
#ifdef OSF1_ENH_SEC
|
|
struct pr_passwd *pw;
|
|
#else /* !OSF1_ENH_SEC */
|
|
struct passwd *pw;
|
|
#ifdef HAVE_SHADOW
|
|
struct spwd *spw;
|
|
|
|
#endif
|
|
#endif /* !OSF1_ENH_SEC */
|
|
pw = (struct passwd *)getpwnam(buffer);
|
|
|
|
if (pw == NULL)
|
|
(void) strcpy(userpass, "*");
|
|
else {
|
|
#ifdef HAVE_SHADOW
|
|
/*-
|
|
* PURIFY on Solaris 2 reports a 1024 byte memory leak on the following line
|
|
* if using NIS compatibility mode, and is internal to libc.so */
|
|
if ((spw = getspnam(pw->pw_name)) != NULL) {
|
|
char *tmp; /* swap */
|
|
|
|
tmp = pw->pw_passwd;
|
|
pw->pw_passwd = spw->sp_pwdp;
|
|
spw->sp_pwdp = tmp;
|
|
}
|
|
endspent();
|
|
#endif
|
|
(void) strcpy(userpass, pw->pw_passwd);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/*-
|
|
* We do not allow for root to have no password, but we handle the case
|
|
* where the user has no password correctly; they have to hit return
|
|
* only.
|
|
*/
|
|
int
|
|
checkPasswd(char *buffer)
|
|
{
|
|
int done = False;
|
|
|
|
#ifdef VMS
|
|
struct ascid password;
|
|
|
|
password.len = strlen(buffer);
|
|
password.dtype = 0;
|
|
password.c_class = 0;
|
|
password.addr = buffer;
|
|
|
|
str$upcase(&password, &password);
|
|
|
|
sys$hash_password(&password, uai_encrypt, uai_salt,
|
|
&username, &hash_system);
|
|
|
|
hash_password[VMS_PASSLENGTH - 1] = 0;
|
|
hash_system[VMS_PASSLENGTH - 1] = 0;
|
|
|
|
done = !strcmp(hash_password, hash_system);
|
|
if (!done && allowroot) {
|
|
sys$hash_password(&password, root_encrypt, root_salt,
|
|
&rootuser, &root_system);
|
|
root_password[VMS_PASSLENGTH - 1] = 0;
|
|
root_system[VMS_PASSLENGTH - 1] = 0;
|
|
done = !strcmp(root_password, root_system);
|
|
}
|
|
#else /* !VMS */
|
|
|
|
#ifdef DCE_PASSWD
|
|
if (usernet)
|
|
done = check_dce_net_passwd(user, buffer);
|
|
else
|
|
done = !strcmp(userpass, crypt(buffer, userpass));
|
|
|
|
if (done)
|
|
return True;
|
|
if (!allowroot)
|
|
return False;
|
|
|
|
if (rootnet)
|
|
done = check_dce_net_passwd(ROOT, buffer);
|
|
else
|
|
done = !strcmp(rootpass, crypt(buffer, rootpass));
|
|
#else /* !DCE_PASSWD */
|
|
|
|
#ifdef USE_PAM
|
|
/*-
|
|
* Use PAM to do authentication. No session logging, only authentication.
|
|
* Bail out if there are any errors.
|
|
* For now, don't try to display strings explaining errors.
|
|
* Later, we could integrate PAM more by posting errors to the
|
|
* user.
|
|
* Query: should we be using PAM_SILENT to shut PAM up?
|
|
*/
|
|
pam_handle_t *pamh;
|
|
int pam_error;
|
|
char *display;
|
|
#ifdef BAD_PAM
|
|
uid_t ruid;
|
|
#define BAD_PAM_SETUID seteuid(ruid);
|
|
#else
|
|
#define BAD_PAM_SETUID
|
|
#endif
|
|
|
|
#define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
|
|
pam_end(pamh, pam_error); BAD_PAM_SETUID return False; \
|
|
}
|
|
#ifdef BAD_PAM
|
|
ruid = getuid(); /* the real user we are running as */
|
|
(void) seteuid(0); /* temporarily go to root so that pam can get shadow password */
|
|
#endif
|
|
#ifdef DEBUG
|
|
(void) printf("PAM: Before: UID (%d), EUID (%d)\n", getuid(), geteuid());
|
|
#endif
|
|
PAM_password = buffer;
|
|
pam_error = pam_start("xlock", user, &PAM_conversation, &pamh);
|
|
PAM_BAIL;
|
|
|
|
display = getenv("DISPLAY");
|
|
if (display != NULL) {
|
|
pam_error = pam_set_item(pamh, PAM_TTY, display);
|
|
PAM_BAIL;
|
|
}
|
|
|
|
pam_error = pam_authenticate(pamh, 0);
|
|
#ifdef DEBUG
|
|
(void) printf("PAM: pam_authenticate returns code (%d)\n", pam_error);
|
|
#endif
|
|
if (pam_error != PAM_SUCCESS) {
|
|
if (!allowroot) {
|
|
PAM_BAIL;
|
|
}
|
|
|
|
/* Try as root; bail if no success there either */
|
|
pam_error = pam_set_item(pamh, PAM_USER, ROOT);
|
|
PAM_BAIL;
|
|
pam_error = pam_authenticate(pamh, 0);
|
|
PAM_BAIL;
|
|
}
|
|
#ifdef BAD_PAM
|
|
(void) seteuid(ruid); /* back to user's privileges */
|
|
#endif
|
|
#ifdef DEBUG
|
|
(void) printf("PAM: After: UID (%d), EUID (%d)\n", getuid(), geteuid());
|
|
#endif
|
|
|
|
/* Seems to cause problems on several systems including GenToo if defined */
|
|
/* https://bugs.gentoo.org/show_bug.cgi?id=96212 */
|
|
#ifdef GOOD_PAM
|
|
pam_error = pam_acct_mgmt(pamh, 0);
|
|
#endif
|
|
if (pam_error == PAM_NEW_AUTHTOK_REQD)
|
|
pam_error = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
|
|
PAM_BAIL;
|
|
|
|
pam_error = pam_setcred(pamh, PAM_REINITIALIZE_CRED);
|
|
PAM_BAIL;
|
|
|
|
pam_end(pamh, PAM_SUCCESS);
|
|
/* If this point is reached, the user has been authenticated. */
|
|
done = True;
|
|
|
|
#else /* !USE_PAM */
|
|
|
|
#ifdef ultrix
|
|
|
|
#ifdef HAVE_SETEUID
|
|
(void) setegid(egid);
|
|
#else
|
|
#ifdef HAVE_SETREUID
|
|
(void) setregid(rgid, egid);
|
|
#endif
|
|
#endif
|
|
done = ((authenticate_user((struct passwd *) getpwnam(user),
|
|
buffer, NULL) >= 0);
|
|
if (!done && allowroot &&
|
|
(authenticate_user((struct passwd *) getpwnam(ROOT),
|
|
buffer, NULL) >= 0))) {
|
|
done = True;
|
|
if (!*buffer)
|
|
/*
|
|
* root has no password, don't let him in...
|
|
*/
|
|
done = False;
|
|
#if ( HAVE_SYSLOG_H && defined( USE_SYSLOG ))
|
|
else
|
|
syslog(SYSLOG_NOTICE, "%s: %s unlocked screen", ProgramName, ROOT);
|
|
#endif
|
|
}
|
|
#ifdef HAVE_SETEUID
|
|
(void) setegid(rgid);
|
|
#else
|
|
#ifdef HAVE_SETREUID
|
|
(void) setregid(egid, rgid);
|
|
#endif
|
|
#endif
|
|
|
|
#else /* !ultrix */
|
|
|
|
#ifdef BSD_AUTH
|
|
char *pass;
|
|
char *style;
|
|
char *name;
|
|
int authok;
|
|
extern gid_t egid, rgid;
|
|
|
|
(void)setegid(egid);
|
|
|
|
#if ( HAVE_FCNTL_H && (defined( USE_MULTIPLE_ROOT ) || defined( USE_MULTIPLE_USER )))
|
|
/* Scan through the linked list until you match a password. Print
|
|
* message to log if password match doesn't equal the user.
|
|
*
|
|
* This should be changed to allow the user name to be typed in also
|
|
* to make this more secure.
|
|
*/
|
|
for (pwll = pwllh; done == 0 && pwll->next; pwll = pwll->next) {
|
|
name = pwll->pw_name;
|
|
#else
|
|
name = user;
|
|
#endif
|
|
if ((pass = strchr(buffer, ':')) != NULL) {
|
|
*pass++ = '\0';
|
|
style = buffer;
|
|
authok = auth_userokay(name, style, "auth-xlock", pass) ||
|
|
auth_userokay(ROOT, style, "auth-xlock", pass);
|
|
*--pass = ':';
|
|
} else
|
|
authok = 0;
|
|
pass = buffer;
|
|
style = NULL;
|
|
if (authok || auth_userokay(name, style, "auth-xlock", pass) ||
|
|
auth_userokay(ROOT, style, "auth-xlock", pass)) {
|
|
done = True;
|
|
#if ( HAVE_SYSLOG_H && defined( USE_SYSLOG ))
|
|
syslog(SYSLOG_NOTICE, "%s: %s unlocked screen", ProgramName,
|
|
ROOT);
|
|
#endif
|
|
}
|
|
#if ( HAVE_FCNTL_H && (defined( USE_MULTIPLE_ROOT ) || defined( USE_MULTIPLE_USER )))
|
|
}
|
|
#endif
|
|
(void)setegid(rgid);
|
|
|
|
#else /* !BSD_AUTH */
|
|
|
|
/* check AFS & SIA passwd first, then local, then root */
|
|
#ifdef AFS
|
|
{
|
|
char *reason;
|
|
|
|
if (!ka_UserAuthenticate(user, "", 0, buffer, 0, &reason))
|
|
return True;
|
|
}
|
|
#endif /* AFS */
|
|
#ifdef SIA
|
|
{
|
|
if ((sia_validate_user(NULL, "xlock", 1, NULL, user, NULL,
|
|
0, NULL, buffer)) == SIASUCCESS)
|
|
return True;
|
|
}
|
|
#endif /* SIA */
|
|
#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
|
|
{
|
|
/* Somehow, buffer gets 'erased' after either doing a krb pw check
|
|
or a reg pw check */
|
|
char buffer2[1024];
|
|
|
|
(void) strncpy(buffer2, buffer, sizeof (buffer2));
|
|
#if 0
|
|
if (!strcmp(userpass, "*"))
|
|
#endif
|
|
#ifdef HAVE_KRB4
|
|
if (krb_check_password((struct passwd *) getpwuid(getuid
|
|
()), buffer2))
|
|
#else
|
|
if (krb_check_password(user, buffer2))
|
|
#endif
|
|
return True;
|
|
}
|
|
#endif /* !HAVE_KRB4 && !HAVE_KRB5 */
|
|
#if ( HAVE_FCNTL_H && (defined( USE_MULTIPLE_ROOT ) || defined( USE_MULTIPLE_USER )))
|
|
if (!done) {
|
|
/* Scan through the linked list until you match a password. Print
|
|
* message to log if password match does not equal the user.
|
|
*
|
|
* This should be changed to allow the user name to be typed in also
|
|
* to make this more secure.
|
|
*/
|
|
for (pwll = pwllh; pwll->next; pwll = pwll->next)
|
|
if (!strcmp((char *) crypt(buffer, pwll->pw_passwd), pwll->pw_passwd)) {
|
|
#if ( HAVE_SYSLOG_H && defined( USE_SYSLOG ))
|
|
if (strcmp(user, pwll->pw_name) != 0)
|
|
syslog(SYSLOG_NOTICE, "%s: %s unlocked screen",
|
|
ProgramName, pwll->pw_name);
|
|
#endif
|
|
return True;
|
|
}
|
|
}
|
|
#endif
|
|
if (!done) {
|
|
#ifdef OSF1_ENH_SEC
|
|
done = (!strcmp((char *) dispcrypt(buffer, userpass, user_oldcrypt), userpass));
|
|
#else
|
|
done = (!strcmp((char *) crypt(buffer, userpass), userpass));
|
|
#endif
|
|
/* userpass is used */
|
|
if (!*userpass && *buffer)
|
|
/*
|
|
* the user has no password, but something was typed anyway.
|
|
* sounds fishy: don't let him in...
|
|
*/
|
|
done = False;
|
|
}
|
|
#if 0
|
|
/* For debugging only! */
|
|
(void) printf("buffer=%s, encrypt=%s, userpass=%s,\n", buffer,
|
|
(char *) crypt(buffer, userpass), userpass);
|
|
#endif
|
|
if (!done && allowroot &&
|
|
#ifdef OSF1_ENH_SEC
|
|
!strcmp((char *) dispcrypt(buffer, rootpass, root_oldcrypt), rootpass)
|
|
#else
|
|
!strcmp((char *) crypt(buffer, rootpass), rootpass)
|
|
#endif
|
|
) {
|
|
done = True;
|
|
if (!(rootpass && *buffer))
|
|
/*
|
|
* root has no password, don't let him in...
|
|
*/
|
|
|
|
done = False;
|
|
#if ( HAVE_SYSLOG_H && defined( USE_SYSLOG ))
|
|
else
|
|
syslog(SYSLOG_NOTICE, "%s: %s unlocked screen", ProgramName, ROOT);
|
|
#endif
|
|
}
|
|
#ifdef USE_XLOCK_GROUP
|
|
if (!done)
|
|
done = checkGroupXlockPasswds(buffer);
|
|
#endif
|
|
#endif /* !BSD_AUTH */
|
|
#endif /* !ultrix */
|
|
#endif /* !USE_PAM */
|
|
#endif /* !DCE_PASSWD */
|
|
#endif /* !VMS */
|
|
|
|
#ifdef PASSWD_HELPER_PROGRAM
|
|
if (!done && !(done = run_helper(user, buffer)) && allowroot)
|
|
done = run_helper(ROOT, buffer);
|
|
#endif
|
|
|
|
return done;
|
|
}
|
|
|
|
/*-
|
|
* Functions for DCE authentication
|
|
*
|
|
* Revision History:
|
|
* 21-Aug-95: Added fallback to static password file [HAK]
|
|
* 06-Jul-95: Mods by Heath A. Kehoe <hakehoe@icaen.uiowa.edu> for
|
|
* inclusion into xlockmore
|
|
* May-95: Created by Phil O'Connell <philo@icaen.uiowa.edu>
|
|
*/
|
|
|
|
#ifdef DCE_PASSWD
|
|
#include <pthread.h>
|
|
#include <dce/sec_login.h>
|
|
#ifdef AIXV3
|
|
#include <userpw.h>
|
|
#endif
|
|
|
|
static void
|
|
initDCE(void)
|
|
{
|
|
sec_login_handle_t login_context;
|
|
error_status_t error_status;
|
|
boolean32 valid;
|
|
struct passwd *pwd;
|
|
|
|
#ifdef AIXV3
|
|
struct userpw *userpwd;
|
|
|
|
#endif
|
|
char *buf;
|
|
|
|
/* test to see if this user exists on the network registry */
|
|
valid = sec_login_setup_identity((unsigned_char_p_t) user,
|
|
sec_login_no_flags, &login_context, &error_status);
|
|
if (!valid) {
|
|
switch (error_status) {
|
|
case sec_rgy_object_not_found:
|
|
break;
|
|
case sec_rgy_server_unavailable:
|
|
(void) fprintf(stderr, "%s: the network registry is not available.\n",
|
|
ProgramName);
|
|
break;
|
|
case sec_login_s_no_memory:
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: out of memory\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
default:
|
|
(void) fprintf(stderr,
|
|
"%s: sec_login_setup_identity() returned status %d\n",
|
|
ProgramName, (int) error_status);
|
|
break;
|
|
}
|
|
|
|
pwd = getpwnam(user);
|
|
if (!pwd || strlen(pwd->pw_passwd) < 10) {
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: could not get user password\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
}
|
|
usernet = 0;
|
|
(void) strcpy(userpass, pwd->pw_passwd);
|
|
} else
|
|
usernet = 1;
|
|
|
|
if (allowroot) {
|
|
#ifdef AIXV3
|
|
userpwd = getuserpw("root");
|
|
(void) strcpy(rootpass, userpwd->upw_passwd);
|
|
if (!(strcmp(rootpass, ""))) {
|
|
(void) fprintf(stderr, "%s: could not get root password\n", ProgramName);
|
|
allowroot = 0;
|
|
} else {
|
|
rootnet = 0;
|
|
}
|
|
#else
|
|
valid = sec_login_setup_identity((unsigned_char_p_t) ROOT,
|
|
sec_login_no_flags, &login_context, &error_status);
|
|
if (!valid) {
|
|
switch (error_status) {
|
|
case sec_rgy_object_not_found:
|
|
break;
|
|
case sec_rgy_server_unavailable:
|
|
(void) fprintf(stderr, "%s: the network registry is not available.\n",
|
|
ProgramName);
|
|
break;
|
|
case sec_login_s_no_memory:
|
|
buf = (char *) malloc(strlen(ProgramName) + 80);
|
|
(void) sprintf(buf,
|
|
"%s: out of memory\n", ProgramName);
|
|
error(buf);
|
|
free(buf); /* Should never get here */
|
|
default:
|
|
(void) fprintf(stderr,
|
|
"%s: sec_login_setup_identity() returned status %d\n",
|
|
ProgramName, (int) error_status);
|
|
break;
|
|
}
|
|
|
|
pwd = getpwuid(0);
|
|
if (!pwd || strlen(pwd->pw_passwd) < 10) {
|
|
(void) fprintf(stderr,
|
|
"%s: could not get root password\n", ProgramName);
|
|
allowroot = 0;
|
|
}
|
|
rootnet = 0;
|
|
(void) strcpy(rootpass, pwd->pw_passwd);
|
|
} else
|
|
rootnet = 1;
|
|
#endif
|
|
}
|
|
pthread_lock_global_np();
|
|
}
|
|
|
|
static char *
|
|
error_string(error_status_t error_status)
|
|
{
|
|
static char buf[60];
|
|
|
|
switch (error_status) {
|
|
case error_status_ok:
|
|
return "no error";
|
|
case sec_rgy_object_not_found:
|
|
return "The principal does not exist";
|
|
case sec_rgy_server_unavailable:
|
|
return "The network registry is not available";
|
|
case sec_login_s_no_memory:
|
|
return "Not enough memory is available to complete the operation";
|
|
case sec_login_s_already_valid:
|
|
return "The login context has already been validated";
|
|
case sec_login_s_default_use:
|
|
return "Can't validate the default context";
|
|
case sec_login_s_acct_invalid:
|
|
return "The account is invalid or has expired";
|
|
case sec_login_s_unsupp_passwd_type:
|
|
return "The password type is not supported";
|
|
case sec_login_s_context_invalid:
|
|
return "The login context itself is not valid";
|
|
default:
|
|
(void) sprintf(buf, "error status #%d", (int) error_status);
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
|
|
/*-
|
|
*----------------------------------------------------------------------
|
|
* Function Created 5/95 to be used with xlock to validate DCE
|
|
* passwords. Routine simply returns a (1) if the the variable
|
|
* PASS is the USER's PASSWORD, else it returns a (0).
|
|
* Functions used:
|
|
*
|
|
* sec_login_setup_identity
|
|
* sec_login_validate_identity
|
|
* sec_login_certify_identity
|
|
*
|
|
* where setup_identity obtains the login context for the USER.
|
|
* This identity is then validated with validate_identity. Finally,
|
|
* cerfify_identity is called to make sure that the Security
|
|
* Server used to set up and validate a login context is legitimate.
|
|
*
|
|
* Created by Phil O'Connell
|
|
* philo@icaen.uiowa.edu
|
|
* Student Programmer
|
|
*
|
|
*-----------------------------------------------------------------------
|
|
*/
|
|
|
|
static int
|
|
check_dce_net_passwd(char *usr, char *pass)
|
|
{
|
|
sec_login_handle_t login_context;
|
|
error_status_t error_status;
|
|
sec_passwd_rec_t password;
|
|
boolean32 reset_password;
|
|
sec_login_auth_src_t auth_src;
|
|
unsigned_char_p_t principal_name;
|
|
boolean32 valid = 0;
|
|
char *passcpy;
|
|
boolean32 current_context;
|
|
|
|
|
|
pthread_unlock_global_np();
|
|
/* -------------------- SETUP IDENTITY--------------------------------- */
|
|
|
|
principal_name = (unsigned_char_p_t) usr;
|
|
|
|
/*
|
|
* We would rather like to refresh and existing login context instead of
|
|
* making a new one.
|
|
*/
|
|
|
|
sec_login_get_current_context(&login_context, &error_status);
|
|
if (error_status != error_status_ok) {
|
|
current_context = 0;
|
|
(void) fprintf(stderr,
|
|
"get_current_context failed! Setting up a new one\n");
|
|
|
|
valid = sec_login_setup_identity(principal_name, sec_login_no_flags,
|
|
&login_context, &error_status);
|
|
|
|
if (!valid) {
|
|
(void) fprintf(stderr, "sec_login_setup_identity() failed: %s\n",
|
|
error_string(error_status));
|
|
pthread_lock_global_np();
|
|
return False;
|
|
}
|
|
} else
|
|
current_context = 1;
|
|
|
|
/*--------------- VALIDATE IDENTITY ---------------------------------*/
|
|
|
|
/* make a copy of pass, because sec_login_validate_identity() will
|
|
clobber the plaintext password passed to it */
|
|
passcpy = (char *) strdup(pass);
|
|
|
|
password.key.key_type = sec_passwd_plain;
|
|
password.key.tagged_union.plain = (unsigned char *) passcpy;
|
|
password.pepper = NULL;
|
|
password.version_number = sec_passwd_c_version_none;
|
|
|
|
valid = sec_login_validate_identity(login_context, &password, &reset_password, &auth_src, &error_status);
|
|
|
|
/* report unusual error conditions */
|
|
if (error_status != error_status_ok &&
|
|
error_status != sec_rgy_passwd_invalid &&
|
|
error_status != sec_login_s_already_valid &&
|
|
error_status != sec_login_s_null_password) {
|
|
(void) fprintf(stderr, "sec_login_validate_identity failed: %s\n",
|
|
error_string(error_status));
|
|
}
|
|
/* done with the copy of the password */
|
|
free(passcpy);
|
|
|
|
/* Refresh the context if we already have one */
|
|
if (current_context) {
|
|
if (!sec_login_refresh_identity(login_context, &error_status)) {
|
|
(void) fprintf(stderr, "sec_login_refresh_identity failed: %s\n",
|
|
error_string(error_status));
|
|
} else {
|
|
passcpy = (char *) strdup(pass);
|
|
|
|
password.key.key_type = sec_passwd_plain;
|
|
password.key.tagged_union.plain = (unsigned char *) passcpy;
|
|
password.pepper = NULL;
|
|
password.version_number = sec_passwd_c_version_none;
|
|
|
|
/* Have to validate the refreshed context */
|
|
valid = sec_login_validate_identity(login_context,
|
|
&password, &reset_password, &auth_src, &error_status);
|
|
|
|
/* report unusual error conditions */
|
|
if (error_status != error_status_ok &&
|
|
error_status != sec_rgy_passwd_invalid &&
|
|
error_status != sec_login_s_null_password) {
|
|
(void) fprintf(stderr, "sec_login_validate_identity failed: %s\n",
|
|
error_string(error_status));
|
|
}
|
|
}
|
|
/* done with the copy of the password */
|
|
free(passcpy);
|
|
}
|
|
/* make sure that the authentication service is not an imposter */
|
|
if (valid) {
|
|
if (!sec_login_certify_identity(login_context, &error_status)) {
|
|
(void) fprintf(stderr, "Authentication service is an imposter!\n");
|
|
/* logoutUser(); */
|
|
valid = 0;
|
|
}
|
|
}
|
|
pthread_lock_global_np();
|
|
return valid;
|
|
}
|
|
|
|
#endif /* DCE_PASSWD */
|
|
|
|
#ifdef HAVE_KRB4
|
|
int
|
|
krb_check_password(struct passwd *pwd, char *pass)
|
|
{
|
|
char realm[REALM_SZ];
|
|
char tkfile[MAXPATHLEN];
|
|
|
|
/* find local realm */
|
|
if (krb_get_lrealm(realm, 1) != KSUCCESS)
|
|
#ifdef KRB_REALM
|
|
/* krb_get_default_realm() may not work well on Solaris */
|
|
(void) strncpy(realm, KRB_REALM, sizeof (realm));
|
|
#else
|
|
(void) strncpy(realm, krb_get_default_realm(), sizeof (realm));
|
|
#endif
|
|
/* Construct a ticket file */
|
|
(void) sprintf(tkfile, "/tmp/tkt_%d", pwd->pw_uid);
|
|
|
|
/* Now, let's make the ticket file named above the _active_ tkt file */
|
|
krb_set_tkt_string(tkfile);
|
|
|
|
/* ask the kerberos server for a ticket! */
|
|
if (krb_get_pw_in_tkt(pwd->pw_name, "", realm,
|
|
"krbtgt", realm,
|
|
DEFAULT_TKT_LIFE,
|
|
pass) == INTK_OK)
|
|
return True;
|
|
return False;
|
|
}
|
|
#endif /* HAVE_KRB4 */
|
|
|
|
#ifdef HAVE_KRB5
|
|
/*
|
|
* This code has been completely rewritten from the original Kerberos code.
|
|
* It now uses the new krb5_get_init_creds() API, and uses a prompter callback
|
|
* (which lives in xlock.c, because it requires a lot of X-windows guts
|
|
* not exposed in this file).
|
|
*
|
|
* The code that would normally write out a new credential cache has been
|
|
* conditionalized under KRB5_WRITE_NEW_CCACHE (--enable-write-krb5 option
|
|
* to configure)
|
|
*/
|
|
|
|
extern krb5_error_code xlock_prompter(krb5_context, void *, const char *,
|
|
const char *, int, krb5_prompt []);
|
|
|
|
static int
|
|
krb_check_password(char *user, char *pass)
|
|
{
|
|
krb5_context kcontext;
|
|
krb5_ccache ccache = NULL;
|
|
krb5_principal me;
|
|
krb5_error_code code;
|
|
krb5_creds my_creds;
|
|
krb5_get_init_creds_opt options;
|
|
char *lifetimestr = NULL;
|
|
krb5_deltat lifetime;
|
|
int option;
|
|
|
|
memset((void *) &my_creds, 0, sizeof (my_creds));
|
|
|
|
krb5_get_init_creds_opt_init(&options);
|
|
|
|
if ((code = krb5_init_context(&kcontext))) {
|
|
com_err(ProgramName, code, "while initializing Kerberos");
|
|
return 0;
|
|
}
|
|
|
|
if (krb5_valid)
|
|
code = krb5_parse_name(kcontext, user, &me);
|
|
|
|
if (! krb5_valid || (krb5_valid && code)) {
|
|
if ((code = krb5_cc_default(kcontext, &ccache))) {
|
|
com_err(ProgramName, code, "while getting default "
|
|
"ccache");
|
|
krb5_free_context(kcontext);
|
|
return 0;
|
|
}
|
|
code = krb5_cc_get_principal(kcontext, ccache, &me);
|
|
if (code) {
|
|
if ((code = krb5_parse_name(kcontext, user, &me))) {
|
|
com_err(ProgramName, code, "when parsing "
|
|
"name %s", user);
|
|
krb5_cc_close(kcontext, ccache);
|
|
krb5_free_context(kcontext);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set all of our various init_creds options
|
|
*/
|
|
|
|
option = 0;
|
|
krb5_appdefault_boolean(kcontext, "xlock",
|
|
krb5_princ_realm(context, me), "forwardable",
|
|
option, &option);
|
|
krb5_get_init_creds_opt_set_forwardable(&options, option);
|
|
|
|
krb5_appdefault_string(kcontext, "xlock", krb5_princ_realm(context, me),
|
|
"default_lifetime", "", &lifetimestr);
|
|
|
|
if (lifetimestr && *lifetimestr) {
|
|
code = krb5_string_to_deltat(lifetimestr, &lifetime);
|
|
if (code == 0)
|
|
krb5_get_init_creds_opt_set_tkt_life(&options,
|
|
lifetime);
|
|
}
|
|
|
|
if (lifetimestr)
|
|
free(lifetimestr);
|
|
|
|
code = krb5_get_init_creds_password(kcontext, &my_creds, me, pass,
|
|
xlock_prompter, NULL, 0, NULL,
|
|
&options);
|
|
|
|
(void) memset(pass, 0, sizeof (pass));
|
|
|
|
if (code) {
|
|
if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
|
|
krb5_free_cred_contents(kcontext, &my_creds);
|
|
if (ccache)
|
|
krb5_cc_close(kcontext, ccache);
|
|
krb5_free_context(kcontext);
|
|
return False; /* bad password entered */
|
|
} else {
|
|
com_err(ProgramName, code, "while getting initial credentials");
|
|
krb5_free_cred_contents(kcontext, &my_creds);
|
|
if (ccache)
|
|
krb5_cc_close(kcontext, ccache);
|
|
krb5_free_context(kcontext);
|
|
return False;
|
|
}
|
|
}
|
|
|
|
#ifdef KRB5_WRITE_NEW_CCACHE
|
|
/*
|
|
* Since the verification has succeeded, a failure at this point
|
|
* will still result in returning a True.
|
|
*/
|
|
|
|
if (!ccache && (code = krb5_cc_default(kcontext, &ccache)))
|
|
com_err(ProgramName, code, "while retrieving default "
|
|
"credential cache");
|
|
|
|
if (!code && (code = krb5_cc_initialize(kcontext, ccache, me)))
|
|
com_err(ProgramName, code, "while initializing credential "
|
|
"cache");
|
|
|
|
if (!code && (code = krb5_cc_store_cred(kcontext, ccache, &my_creds)))
|
|
com_err(ProgramName, code, "while storing credentials");
|
|
|
|
#endif /* KRB5_WRITE_NEW_CCACHE */
|
|
|
|
if (ccache)
|
|
krb5_cc_close(kcontext, ccache);
|
|
|
|
krb5_free_cred_contents(kcontext, &my_creds);
|
|
|
|
krb5_free_context(kcontext);
|
|
|
|
return True; /* success */
|
|
}
|
|
#endif /* HAVE_KRB5 */
|
|
|
|
#ifndef VMS
|
|
#undef passwd
|
|
#undef pw_name
|
|
#undef pw_passwd
|
|
#ifndef SUNOS_ADJUNCT_PASSWD
|
|
#include <pwd.h>
|
|
#endif
|
|
#endif
|
|
|
|
#if ( HAVE_FCNTL_H && (defined( USE_MULTIPLE_ROOT ) || defined( USE_MULTIPLE_USER )))
|
|
|
|
void
|
|
get_multiple(struct passwd *pw)
|
|
{
|
|
/* This should be the first element on the linked list.
|
|
* If not, then there could be problems.
|
|
* Also all memory allocations tend to force an exit of
|
|
* the program. This should probably be changed somehow.
|
|
*/
|
|
if (pwllh == (pwlptr) NULL) {
|
|
if ((pwll = new_pwlnode()) == (pwlptr) ENOMEM) {
|
|
perror("new");
|
|
exit(1);
|
|
}
|
|
pwllh = pwll;
|
|
}
|
|
if ((pwll->pw_name = (char *) strdup(pw->pw_name)) == NULL) {
|
|
perror("new");
|
|
exit(1);
|
|
}
|
|
#ifndef BSD_AUTH
|
|
if ((pwll->pw_passwd = (char *) strdup(pw->pw_passwd)) == NULL) {
|
|
perror("new");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
if ((pwll->next = new_pwlnode()) == (pwlptr) ENOMEM) {
|
|
perror("new");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void
|
|
set_multiple(int uid)
|
|
{
|
|
#ifdef BSD_AUTH
|
|
struct passwd *pw;
|
|
pwlptr pwll;
|
|
|
|
if (pwllh == (pwlptr) NULL) {
|
|
if ((pwll = new_pwlnode()) == (pwlptr) ENOMEM) {
|
|
perror("new");
|
|
exit(1);
|
|
}
|
|
pwllh = pwll;
|
|
}
|
|
for (pwll = pwllh; pwll->next; pwll = pwll->next);
|
|
|
|
while ((pw = getpwent()) != (struct passwd *) NULL) {
|
|
if (pw->pw_uid != uid)
|
|
continue;
|
|
if ((pwll->pw_name = (char *) strdup(pw->pw_name)) == NULL) {
|
|
perror("new");
|
|
exit(1);
|
|
}
|
|
|
|
if ((pwll->next = new_pwlnode()) == (pwlptr) ENOMEM) {
|
|
perror("new");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (pwll->next = new_pwlnode())
|
|
pwll = pwll->next;
|
|
#else /* !BSD_AUTH */
|
|
/* If you thought the above was sick, then you will think this is
|
|
* downright horrific. This is set up so that a child process
|
|
* is created to read in the password entries using getpwent(3C).
|
|
* In the man pages on the HPs, getpwent(3C) has in it the fact
|
|
* that once getpwent(3C) has opened the password file, it keeps
|
|
* it open until the process is finished. Thus, the child
|
|
* process exits immediately after reading the entire password
|
|
* file. Otherwise, the password file remains open the entire
|
|
* time this program is running.
|
|
*
|
|
* I went with getpwent(3C) because it will actually read in
|
|
* the password entries from the NIS maps as well.
|
|
*/
|
|
struct passwd *pw;
|
|
int pipefd[2];
|
|
char buf[BUFMAX], xlen;
|
|
pid_t cid;
|
|
|
|
#ifdef HAVE_SHADOW
|
|
struct spwd *spw;
|
|
|
|
#endif
|
|
|
|
if (pipe(pipefd) < 0) {
|
|
perror("Pipe Generation");
|
|
exit(1);
|
|
}
|
|
if ((cid = fork()) < 0) {
|
|
perror("fork");
|
|
exit(1);
|
|
} else if (cid == 0) {
|
|
/* child process. Used to read in password file. Also checks to
|
|
* see if the uid is one we want. If so, then writes that to the pipe.
|
|
*/
|
|
register int sbuf = 0;
|
|
char *cbuf, *pbuf;
|
|
|
|
(void) close(pipefd[0]);
|
|
while ((pw = getpwent()) != (struct passwd *) NULL) {
|
|
if (pw->pw_uid != uid)
|
|
continue;
|
|
#ifdef HAVE_SHADOW
|
|
/*-
|
|
* PURIFY on Solaris 2 reports a 1024 byte memory leak on the following line
|
|
* if using NIS compatibility mode, and is internal to libc.so */
|
|
if ((spw = getspnam(pw->pw_name)) != NULL) {
|
|
char *tmp; /* swap */
|
|
|
|
tmp = pw->pw_passwd;
|
|
pw->pw_passwd = spw->sp_pwdp;
|
|
spw->sp_pwdp = tmp;
|
|
}
|
|
#endif
|
|
if (pw->pw_passwd[0] != '*') {
|
|
xlen = strlen(pw->pw_name);
|
|
if ((sbuf + xlen) >= BUFMAX) {
|
|
if (write(pipefd[1], buf, sbuf) != sbuf)
|
|
perror("write");
|
|
sbuf = 0;
|
|
}
|
|
cbuf = &buf[sbuf];
|
|
*cbuf++ = xlen;
|
|
for (pbuf = pw->pw_name; *pbuf;)
|
|
*cbuf++ = *pbuf++;
|
|
sbuf += xlen + 1;
|
|
|
|
xlen = strlen(pw->pw_passwd);
|
|
if ((sbuf + xlen) >= BUFMAX) {
|
|
if (write(pipefd[1], buf, sbuf) != sbuf)
|
|
perror("write");
|
|
sbuf = 0;
|
|
}
|
|
cbuf = &buf[sbuf];
|
|
*cbuf++ = xlen;
|
|
for (pbuf = pw->pw_passwd; *pbuf;)
|
|
*cbuf++ = *pbuf++;
|
|
sbuf += xlen + 1;
|
|
}
|
|
}
|
|
#ifdef HAVE_SHADOW
|
|
endspent();
|
|
#endif
|
|
cbuf = &buf[sbuf];
|
|
*cbuf = -1;
|
|
sbuf++;
|
|
if (write(pipefd[1], buf, sbuf) != sbuf)
|
|
perror("write");
|
|
|
|
(void) close(pipefd[1]);
|
|
exit(0);
|
|
} else {
|
|
/* parent process. Does the actual creation of the linked list.
|
|
* It assumes that everything coming through the pipe are password
|
|
* entries that are authorized to unlock the screen.
|
|
*/
|
|
register int bufsize = BUFMAX, done = 0, sbuf = BUFMAX,
|
|
i;
|
|
char *cbuf, *pbuf;
|
|
pwlptr pwll;
|
|
|
|
(void) close(pipefd[1]);
|
|
|
|
if (pwllh == (pwlptr) NULL) {
|
|
if ((pwll = new_pwlnode()) == (pwlptr) ENOMEM) {
|
|
perror("new");
|
|
exit(1);
|
|
}
|
|
pwllh = pwll;
|
|
}
|
|
for (pwll = pwllh; pwll->next; pwll = pwll->next);
|
|
while (!done) {
|
|
if (sbuf >= bufsize) {
|
|
if ((bufsize = read(pipefd[0], buf, BUFMAX)) <= 0)
|
|
perror("read");
|
|
sbuf = 0;
|
|
}
|
|
cbuf = &buf[sbuf];
|
|
xlen = *cbuf++;
|
|
if (xlen < 0) {
|
|
done = 1;
|
|
break;
|
|
}
|
|
sbuf++;
|
|
if (sbuf >= bufsize) {
|
|
if ((bufsize = read(pipefd[0], buf, BUFMAX)) <= 0)
|
|
perror("read");
|
|
sbuf = 0;
|
|
}
|
|
if ((pwll->pw_name = (char *) malloc(xlen + 1)) == NULL)
|
|
break;
|
|
pbuf = pwll->pw_name;
|
|
cbuf = &buf[sbuf];
|
|
for (i = 0; i < xlen; i++) {
|
|
*pbuf++ = *cbuf++;
|
|
sbuf++;
|
|
if (sbuf >= bufsize) {
|
|
if ((bufsize = read(pipefd[0], buf, BUFMAX)) <= 0)
|
|
perror("read");
|
|
sbuf = 0;
|
|
cbuf = buf;
|
|
}
|
|
}
|
|
*pbuf = (char) NULL;
|
|
|
|
cbuf = &buf[sbuf];
|
|
xlen = *cbuf++;
|
|
sbuf++;
|
|
if (sbuf >= bufsize) {
|
|
if ((bufsize = read(pipefd[0], buf, BUFMAX)) <= 0)
|
|
perror("read");
|
|
sbuf = 0;
|
|
}
|
|
if ((pwll->pw_passwd = (char *) malloc(xlen + 1)) == NULL)
|
|
break;
|
|
pbuf = pwll->pw_passwd;
|
|
cbuf = &buf[sbuf];
|
|
for (i = 0; i < xlen; i++) {
|
|
*pbuf++ = *cbuf++;
|
|
sbuf++;
|
|
if (sbuf >= bufsize) {
|
|
if ((bufsize = read(pipefd[0], buf, BUFMAX)) <= 0)
|
|
perror("read");
|
|
sbuf = 0;
|
|
cbuf = buf;
|
|
}
|
|
}
|
|
*pbuf = (char) NULL;
|
|
|
|
if ((pwll->next = new_pwlnode()) == (pwlptr) ENOMEM)
|
|
break;
|
|
pwll = pwll->next;
|
|
}
|
|
(void) close(pipefd[0]);
|
|
}
|
|
#endif /* !BSD_AUTH */
|
|
}
|
|
|
|
#endif
|
|
|
|
void
|
|
initPasswd(void)
|
|
{
|
|
getUserName();
|
|
#if !defined( ultrix ) && !defined( DCE_PASSWD ) && !defined( USE_PAM ) && !defined(BSD_AUTH)
|
|
if (!nolock && !inroot && !inwindow && grabmouse) {
|
|
#ifdef USE_XLOCKRC
|
|
gpass();
|
|
#else
|
|
#ifdef FALLBACK_XLOCKRC
|
|
if (!cpasswd || !*cpasswd)
|
|
getCryptedUserPasswd();
|
|
else
|
|
gpass();
|
|
#else
|
|
getCryptedUserPasswd();
|
|
#endif
|
|
#endif
|
|
if (allowroot)
|
|
getCryptedRootPasswd();
|
|
#ifdef USE_XLOCK_GROUP
|
|
getCryptedXlockGroupPasswds();
|
|
#endif
|
|
}
|
|
#endif /* !ultrix && !DCE_PASSWD && !USE_PAM */
|
|
#ifdef DCE_PASSWD
|
|
initDCE();
|
|
#endif
|
|
}
|
|
|
|
#ifdef USE_XLOCK_GROUP
|
|
/*
|
|
** FUNCTION checkXlockgrp
|
|
** AUTHOR Rich Anderson
|
|
** ABSTRACT This function queries the NIS/NIS+/local group databases to check
|
|
** for the xlock group. It then looks through the users within the
|
|
** group to check the inputted password belongs to member of the
|
|
** group. It returns unlock. valid = 1
|
|
*/
|
|
|
|
#ifndef GROUP
|
|
#define GROUP "xlock"
|
|
#endif
|
|
|
|
#define PASSLENGTH1 (PASSLENGTH+1)
|
|
static void
|
|
getCryptedXlockGroupPasswds()
|
|
{
|
|
int i = 0, num = 0;
|
|
struct passwd *pw;
|
|
struct group *grp;
|
|
#ifdef HAVE_SHADOW
|
|
struct spwd *spw;
|
|
#endif
|
|
if (!(grp = getgrnam(GROUP))) {
|
|
/* The group xlock does not exist. */
|
|
return;
|
|
}
|
|
if (!grp->gr_mem[0]) {
|
|
return;
|
|
}
|
|
while (grp->gr_mem[num]) {
|
|
num++;
|
|
}
|
|
if ((grouppass = (char *) malloc(num * PASSLENGTH1 * sizeof (char))) == NULL) {
|
|
return;
|
|
}
|
|
while (grp->gr_mem[i]) {
|
|
pw = (struct passwd *)getpwnam(grp->gr_mem[i]);
|
|
|
|
if (pw == NULL)
|
|
(void) strcpy(&grouppass[i * PASSLENGTH1], "*");
|
|
else {
|
|
|
|
#ifdef HAVE_SHADOW
|
|
/*-
|
|
* PURIFY on Solaris 2 reports a 1024 byte memory leak on the following line
|
|
* if using NIS compatibility mode, and is internal to libc.so */
|
|
if ((spw = getspnam(pw->pw_name)) != NULL) {
|
|
char *tmp; /* swap */
|
|
|
|
tmp = pw->pw_passwd;
|
|
pw->pw_passwd = spw->sp_pwdp;
|
|
spw->sp_pwdp = tmp;
|
|
}
|
|
endspent();
|
|
#endif
|
|
(void) strcpy(&grouppass[i * PASSLENGTH1], pw->pw_passwd);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
int checkGroupXlockPasswds(char *buffer)
|
|
{
|
|
struct group *grp;
|
|
int i = 0;
|
|
int unlock = 0;
|
|
|
|
if (!(grp = getgrnam(GROUP))) {
|
|
/* The group xlock does not exist. */
|
|
return False;
|
|
}
|
|
if (!grouppass)
|
|
return False;
|
|
if (!*buffer) {
|
|
/* The password buffer is blank. */
|
|
return False;
|
|
}
|
|
while (grp->gr_mem[i]) {
|
|
#ifdef OSF1_ENH_SEC
|
|
unlock = (!strcmp((char *) dispcrypt(buffer, &grouppass[i * PASSLENGTH1], user_oldcrypt), &grouppass[i * PASSLENGTH1]));
|
|
#else
|
|
unlock = (!strcmp((char *) crypt(buffer, &grouppass[i * PASSLENGTH1]), &grouppass[i * PASSLENGTH1]));
|
|
#endif
|
|
#if 0
|
|
/* For debugging only! */
|
|
(void) printf("gbuffer=%s, encrypt=%s, grouppass=%s,\n", buffer,
|
|
(char *) crypt(buffer, grouppass[i]), &grouppass[i * PASSLENGTH1]);
|
|
#endif
|
|
if (unlock) {
|
|
#if ( HAVE_SYSLOG_H && defined( USE_SYSLOG ))
|
|
syslog(SYSLOG_NOTICE, "%s: %s unlocked screen for %s", ProgramName, grp->gr_mem[i], user);
|
|
#endif
|
|
return unlock;
|
|
}
|
|
i++;
|
|
}
|
|
return False;
|
|
}
|
|
#endif
|
|
|
|
#ifdef PASSWD_HELPER_PROGRAM
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
static int
|
|
run_helper(const char *user, const char *pass)
|
|
{
|
|
sigset_t sigset;
|
|
int pfd[2], status;
|
|
pid_t pid;
|
|
|
|
if (pipe(pfd) < 0)
|
|
return 0;
|
|
|
|
sigemptyset(&sigset);
|
|
sigaddset(&sigset, SIGCHLD);
|
|
sigprocmask(SIG_BLOCK, &sigset, &sigset);
|
|
|
|
if ((pid = fork()) < 0) {
|
|
close(pfd[0]);
|
|
close(pfd[1]);
|
|
return 0;
|
|
}
|
|
|
|
if (pid == 0) {
|
|
close(pfd[1]);
|
|
if (pfd[0] != 0)
|
|
dup2(pfd[0], 0);
|
|
|
|
/* Helper is invoked as helper service-name [user] */
|
|
execlp(PASSWD_HELPER_PROGRAM, PASSWD_HELPER_PROGRAM,"xlock", user, NULL);
|
|
error("Failed to execute " PASSWD_HELPER_PROGRAM);
|
|
exit(1);
|
|
}
|
|
|
|
close(pfd[0]);
|
|
|
|
/* Write out password to helper process */
|
|
if (!pass)
|
|
pass = "";
|
|
write(pfd[1], pass, strlen(pass));
|
|
close(pfd[1]);
|
|
|
|
while (waitpid(pid, &status, 0) < 0) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
sigprocmask(SIG_SETMASK, &sigset, NULL);
|
|
return 0;
|
|
}
|
|
|
|
sigprocmask(SIG_SETMASK, &sigset, NULL);
|
|
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
#endif
|