Files
mars-smart/check_login.c
Mario Fetka 02b7984e17 add readme
2026-05-22 09:40:02 +02:00

176 lines
3.5 KiB
C

/*
SMArT
Check username/password combination using PAM and require membership in
the configured SMArT administrator Unix group.
Copyright 2001 Wilmer van der Gaast
Updated for MARS_NWE SMArT group-restricted login.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <security/pam_appl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int my_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr);
static int user_in_group(const char *username, const char *groupname);
static struct pam_conv conv = {
my_conv,
NULL
};
char *user;
char *pass;
int main( int argc, char **argv )
{
pam_handle_t *pamh = NULL;
int retval, st = 1;
const char *admin_group;
if( argc < 4 )
{
fprintf( stderr, "Usage: %s <user> <password> <admin-group>\n", argv[0] );
return( 3 );
}
user = argv[1];
pass = argv[2];
admin_group = argv[3];
if( user == NULL || user[0] == '\0' ||
pass == NULL ||
admin_group == NULL || admin_group[0] == '\0' )
{
return( 3 );
}
retval = pam_start( "smart", user, &conv, &pamh );
if( retval == PAM_SUCCESS )
retval = pam_authenticate( pamh, PAM_SILENT );
if( retval == PAM_SUCCESS )
st = retval = pam_acct_mgmt( pamh, PAM_SILENT );
if( pamh != NULL && pam_end( pamh, retval ) != PAM_SUCCESS )
return( 1 );
if( st != PAM_SUCCESS )
return( 1 );
if( ! user_in_group( user, admin_group ) )
return( 2 );
return( 0 );
}
static int user_in_group(const char *username, const char *groupname)
{
struct passwd *pw;
struct group *gr;
int ngroups = 0;
gid_t *groups;
int i;
if( username == NULL || username[0] == '\0' ||
groupname == NULL || groupname[0] == '\0' )
{
return( 0 );
}
pw = getpwnam( username );
gr = getgrnam( groupname );
if( pw == NULL || gr == NULL )
{
return( 0 );
}
if( pw->pw_gid == gr->gr_gid )
{
return( 1 );
}
#if defined(__linux__) || defined(__GLIBC__)
/*
getgrouplist() asks NSS for supplementary groups, so files, LDAP, SSSD,
NIS, etc. follow the local nsswitch.conf configuration.
*/
getgrouplist( username, pw->pw_gid, NULL, &ngroups );
if( ngroups > 0 )
{
groups = calloc( (size_t) ngroups, sizeof( gid_t ) );
if( groups != NULL )
{
if( getgrouplist( username, pw->pw_gid, groups, &ngroups ) >= 0 )
{
for( i = 0; i < ngroups; i++ )
{
if( groups[i] == gr->gr_gid )
{
free( groups );
return( 1 );
}
}
}
free( groups );
}
}
#endif
/*
Portable fallback: check the group's explicit member list.
*/
if( gr->gr_mem != NULL )
{
for( i = 0; gr->gr_mem[i] != NULL; i++ )
{
if( strcmp( gr->gr_mem[i], username ) == 0 )
{
return( 1 );
}
}
}
return( 0 );
}
int my_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
struct pam_response *reply;
int i;
(void) msg;
(void) appdata_ptr;
reply = (struct pam_response *) calloc( (size_t) num_msg, sizeof( struct pam_response ) );
if( reply == NULL )
{
return( PAM_BUF_ERR );
}
for( i = 0; i < num_msg; i ++ )
{
reply[i].resp = (char *) strdup( pass ); /* Just give the password... It's all we know */
reply[i].resp_retcode = 0;
}
*resp = reply;
return( PAM_SUCCESS );
}