1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
/*
* system-level password checking for host auth mode
* by Nathan Bryant, March 1999
* updated by Trey van Riper, June 2005
*
* Copyright (c) 1999-2016 by the citadel.org team
*
* This program is open source software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#if defined(__linux) || defined(__sun) /* needed for crypt(): */
#define _XOPEN_SOURCE
#define _XOPEN_SOURCE_EXTENDED 1
#endif
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "auth.h"
#include "sysdep.h"
#ifdef HAVE_GETSPNAM
#include <shadow.h>
#endif
#ifdef HAVE_PAM_START
#include <security/pam_appl.h>
/*
* struct appdata: passed to the conversation function
*/
struct appdata
{
const char *name;
const char *pw;
};
/*
* conv(): the PAM conversation function. this assumes that a
* PAM_PROMPT_ECHO_ON is asking for a username, and a PAM_PROMPT_ECHO_OFF is
* asking for a password. esoteric authentication modules will fail with this
* code, but we can't really support them with the existing client protocol
* anyway. the failure mode should be to deny access, in any case.
*/
static int conv(int num_msg, const struct pam_message **msg,
struct pam_response **resp, void *appdata_ptr)
{
struct pam_response *temp_resp;
struct appdata *data = appdata_ptr;
if ((temp_resp = malloc(sizeof(struct pam_response[num_msg]))) == NULL)
return PAM_CONV_ERR;
while (num_msg--)
{
switch ((*msg)[num_msg].msg_style)
{
case PAM_PROMPT_ECHO_ON:
temp_resp[num_msg].resp = strdup(data->name);
break;
case PAM_PROMPT_ECHO_OFF:
temp_resp[num_msg].resp = strdup(data->pw);
break;
default:
temp_resp[num_msg].resp = NULL;
}
temp_resp[num_msg].resp_retcode = 0;
}
*resp = temp_resp;
return PAM_SUCCESS;
}
#endif /* HAVE_PAM_START */
/*
* check that `pass' is the correct password for `uid'
* returns zero if no, nonzero if yes
*/
int validate_password(uid_t uid, const char *pass)
{
if (pass == NULL) {
return(0);
}
#ifdef HAVE_PAM_START
struct pam_conv pc;
struct appdata data;
pam_handle_t *ph;
int i;
#else
char *crypted_pwd;
#ifdef HAVE_GETSPNAM
struct spwd *sp;
#endif
#endif
struct passwd *pw;
int retval = 0;
pw = getpwuid(uid);
if (pw == NULL) {
return retval;
}
#ifdef HAVE_PAM_START
#ifdef PAM_DATA_SILENT
int flags = PAM_DATA_SILENT;
#else
int flags = 0;
#endif
pc.conv = conv;
pc.appdata_ptr = &data;
data.name = pw->pw_name;
data.pw = pass;
if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS)
return(0);
if ((i = pam_authenticate(ph, flags)) == PAM_SUCCESS) {
if ((i = pam_acct_mgmt(ph, flags)) == PAM_SUCCESS) {
retval = -1;
}
}
pam_end(ph, i | flags);
#else
crypted_pwd = pw->pw_passwd;
#ifdef HAVE_GETSPNAM
if (pw == NULL) return(0);
if (pw->pw_name == NULL) return(0);
if ((sp = getspnam(pw->pw_name)) != NULL) {
crypted_pwd = sp->sp_pwdp;
}
#endif
if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd)) {
retval = -1;
}
#endif /* HAVE_PAM_START */
return retval;
}
|