blob: 100168c5526fb5023f8f1ac8d9e071f83e91ac25 [file] [log] [blame]
/*
// Copyright (c) 2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#include <syslog.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <security/pam_ext.h>
#include <security/pam_modules.h>
#include <security/pam_modutil.h>
#define MAX_SPEC_GRP_PASS_LENGTH 20
#define MAX_SPEC_GRP_USER_LENGTH 16
/*
* This module is intended to verify special group user password matches the
* restrictions needed.
*
* Note: Other than for pam_chauthtok(), pam_ipmicheck module should not be
* used for other purpose like authentication, session & account management.
* This module has to be used along with pam_ipmisave module, which will save
* the passwords of the special group users.
*/
static const char *get_option(const pam_handle_t *pamh, const char *option,
int argc, const char **argv)
{
int i = 0;
size_t len = strlen(option);
for (i = 0; i < argc; ++i) {
if (strncmp(option, argv[i], len) == 0) {
if (argv[i][len] == '=') {
return &argv[i][len + 1];
}
}
}
return NULL;
}
/* Password Management API's */
int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
int retval = -1;
const void *item = NULL;
const char *user = NULL;
const char *pass_new = NULL, *pass_old = NULL;
const char *spec_grp_name =
get_option(pamh, "spec_grp_name", argc, argv);
pam_syslog(pamh, LOG_DEBUG, "Special group name is %s", spec_grp_name);
if (spec_grp_name == NULL) {
return PAM_IGNORE;
}
if (flags & PAM_PRELIM_CHECK) {
// send success to verify other stacked modules prelim check.
pam_syslog(pamh, LOG_DEBUG, "PRELIM_CHECK Called");
return PAM_SUCCESS;
}
// Read new password.
// Note: Subsequent modules must use stacked password option use_authtok
retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass_new, NULL);
if (retval != PAM_SUCCESS) {
pam_syslog(pamh, LOG_ERR,
"password - unable to get new password");
return retval;
}
retval = pam_get_user(pamh, &user, NULL);
if (retval != PAM_SUCCESS) {
return retval;
}
struct group *grp;
int spec_grp_usr = 0;
// Verify whether the user belongs to special group.
grp = pam_modutil_getgrnam(pamh, spec_grp_name);
if (grp != NULL) {
while (*(grp->gr_mem) != NULL) {
if (strcmp(user, *grp->gr_mem) == 0) {
spec_grp_usr = 1;
break;
}
(grp->gr_mem)++;
}
}
if (spec_grp_usr) {
// verify the new password is acceptable.
size_t pass_len = strlen(pass_new);
size_t user_len = strlen(user);
if (pass_len > MAX_SPEC_GRP_PASS_LENGTH
|| user_len > MAX_SPEC_GRP_USER_LENGTH) {
pam_syslog(
pamh, LOG_ERR,
"Password length (%zu) / User name length (%zu) is not acceptable for IPMI",
pass_len, user_len);
pam_error(
pamh,
"Username %zu / Password %zu exceeds IPMI 16/20 limit",
user_len, pass_len);
pass_new = pass_old = NULL;
return PAM_AUTHTOK_ERR;
}
}
return PAM_SUCCESS;
}
/* end of module definition */