login: add login.defs code and tests

The new logindefs.c file contains /etc/login.defs parser and functions
for searching in the list of the login default variables. The patch
also contains a new regression test for the code.

Based on pam_login-4.0 from Suse.

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2011-10-05 12:10:26 +02:00
parent c293a7e8ae
commit c82d9c977c
9 changed files with 317 additions and 1 deletions

View File

@ -72,6 +72,8 @@
/* used in term-utils/agetty.c */
#define _PATH_ISSUE "/etc/issue"
#define _PATH_LOGINDEFS "/etc/login.defs"
/* used in misc-utils/look.c */
#define _PATH_WORDS "/usr/share/dict/words"
#define _PATH_WORDS_ALT "/usr/share/dict/web2"

View File

@ -1,4 +1,5 @@
test_islocal
test_logindefs
chfn
chsh
login

View File

@ -65,6 +65,9 @@ install-exec-hook::
endif
noinst_PROGRAMS = test_islocal
noinst_PROGRAMS = test_islocal test_logindefs
test_islocal_SOURCES = islocal.c
test_islocal_CPPFLAGS = -DTEST_PROGRAM $(AM_CPPFLAGS)
test_logindefs_SOURCES = logindefs.c logindefs.h
test_logindefs_CPPFLAGS = -DTEST_PROGRAM $(AM_CPPFLAGS)

246
login-utils/logindefs.c Normal file
View File

@ -0,0 +1,246 @@
/*
* Copyright (C) 2003, 2004, 2005 Thorsten Kukuk
* Author: Thorsten Kukuk <kukuk@suse.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain any existing copyright
* notice, and this entire permission notice in its entirety,
* including the disclaimer of warranties.
*
* 2. Redistributions in binary form must reproduce all prior and current
* copyright notices, this list of conditions, and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. The name of any author may not be used to endorse or promote
* products derived from this software without their specific prior
* written permission.
*/
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include <sys/syslog.h>
#include "c.h"
#include "nls.h"
#include "xalloc.h"
#include "pathnames.h"
#include "logindefs.h"
struct item {
char *name; /* name of the option. */
char *value; /* value of the option. */
char *path; /* name of config file for this option. */
struct item *next; /* pointer to next option. */
};
static struct item *list = NULL;
void free_getlogindefs_data(void)
{
struct item *ptr;
ptr = list;
while (ptr) {
struct item *tmp = ptr->next;
free(ptr->path);
free(ptr->name);
free(ptr->value);
free(ptr);
ptr = tmp;
}
list = NULL;
}
static void store(const char *name, const char *value, const char *path)
{
struct item *new = xmalloc(sizeof(struct item));
if (!name)
abort();
new->name = xstrdup(name);
new->value = value && *value ? xstrdup(value) : NULL;
new->path = xstrdup(path);
new->next = list;
list = new;
}
static void load_defaults(const char *filename)
{
FILE *f;
char buf[BUFSIZ];
f = fopen(filename, "r");
if (!f)
return;
while (fgets(buf, sizeof(buf), f)) {
char *p, *name, *data = NULL;
if (*buf == '#' || *buf == '\n')
continue; /* only comment or empty line */
p = strchr(buf, '#');
if (p)
*p = '\0';
else {
size_t n = strlen(buf);
if (n && *(buf + n - 1) == '\n')
*(buf + n - 1) = '\0';
}
if (!*buf)
continue; /* empty line */
/* ignore space at begin of the line */
name = buf;
while (*name && isspace((unsigned) *name))
name++;
/* go to the end of the name */
data = name;
while (*data && !(isspace((unsigned) *data) || *data == '='))
data++;
if (data > name && *data)
*data++ = '\0';
if (!*name || data == name)
continue;
/* go to the begin of the value */
while (*data && (isspace((unsigned) *data) || *data == '=' || *data == '"'))
data++;
/* remove space at the end of the value */
p = data + strlen(data);
if (p > data)
p--;
while (p > data && (isspace((unsigned) *p) || *p == '"'))
*p-- = '\0';
store(name, data, filename);
}
fclose(f);
}
static struct item *search(const char *name)
{
struct item *ptr;
if (!list)
load_defaults(_PATH_LOGINDEFS);
ptr = list;
while (ptr != NULL) {
if (strcasecmp(name, ptr->name) == 0)
return ptr;
ptr = ptr->next;
}
return NULL;
}
static const char *search_config(const char *name)
{
struct item *ptr;
ptr = list;
while (ptr != NULL) {
if (strcasecmp(name, ptr->name) == 0)
return ptr->path;
ptr = ptr->next;
}
return NULL;
}
int getlogindefs_bool(const char *name, int dflt)
{
struct item *ptr= search(name);
return ptr && ptr->value ? (strcasecmp(ptr->value, "yes") == 0) : dflt;
}
long getlogindefs_num(const char *name, long dflt)
{
struct item *ptr = search(name);
char *end = NULL;
long retval;
if (!ptr || !ptr->value)
return dflt;
errno = 0;
retval = strtol(ptr->value, &end, 0);
if (end && *end == '\0' && !errno)
return retval;
syslog(LOG_NOTICE, _("%s: %s contains invalid numerical value: %s"),
search_config(name), name, ptr->value);
return dflt;
}
/*
* Returns:
* @dflt if @name not found
* "" (empty string) if found, but value not defined
* "string" if found
*/
const char *getlogindefs_str(const char *name, const char *dflt)
{
struct item *ptr = search(name);
if (!ptr)
return dflt;
if (!ptr->value)
return "";
return ptr->value;
}
#ifdef TEST_PROGRAM
int main(int argc, char *argv[])
{
char *name, *type;
if (argc <= 1)
errx(EXIT_FAILURE, "usage: %s <filename> "
"[<str|num|bool> <valname>]", argv[0]);
load_defaults(argv[1]);
if (argc != 4) { /* list all */
struct item *ptr;
for (ptr = list; ptr; ptr = ptr->next)
printf("%s: $%s: '%s'\n", ptr->path, ptr->name, ptr->value);
return EXIT_SUCCESS;
}
type = argv[2];
name = argv[3];
if (strcmp(type, "str") == 0)
printf("$%s: '%s'\n", name, getlogindefs_str(name, "DEFAULT"));
else if (strcmp(type, "num") == 0)
printf("$%s: '%ld'\n", name, getlogindefs_num(name, 0));
else if (strcmp(type, "bool") == 0)
printf("$%s: '%s'\n", name, getlogindefs_bool(name, 0) ? "Y" : "N");
return EXIT_SUCCESS;
}
#endif

9
login-utils/logindefs.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef UTIL_LINUX_LOGINDEFS_H
#define UTIL_LINUX_LOGINDEFS_H
extern int getlogindefs_bool(const char *name, int dflt);
extern long getlogindefs_num(const char *name, long dflt);
extern const char *getlogindefs_str(const char *name, const char *dflt);
extern void free_getlogindefs_data(void);
#endif /* UTIL_LINUX_LOGINDEFS_H */

View File

@ -25,6 +25,7 @@ TS_HELPER_LIBMOUNT_CONTEXT="$top_builddir/libmount/src/test_context"
TS_HELPER_LIBMOUNT_TABDIFF="$top_builddir/libmount/src/test_tab_diff"
TS_HELPER_ISLOCAL="$top_builddir/login-utils/test_islocal"
TS_HELPER_LOGINDEFS="$top_builddir/login-utils/test_logindefs"
# TODO: use partx
TS_HELPER_PARTITIONS="$top_builddir/libblkid/samples/partitions"

View File

@ -0,0 +1,14 @@
logindefs.data: $END: 'the is end'
logindefs.data: $EMPTY: '(null)'
logindefs.data: $CRAZY3: 'FoooBaaar'
logindefs.data: $CRAZY2: 'fooBar'
logindefs.data: $CRAZY1: 'this is crazy format'
logindefs.data: $BOOLEAN: 'yEs'
logindefs.data: $NUMBER: '123456'
logindefs.data: $STRING: 'this_is_string'
logindefs.data: $HELLO_WORLD: 'hello world!'
$STRING: 'this_is_string'
$NUMBER: '123456'
$BOOLEAN: 'Y'
$EMPTY: ''
$UNKNOWN: 'DEFAULT'

24
tests/ts/login/logindefs Executable file
View File

@ -0,0 +1,24 @@
#!/bin/bash
#
# Copyright (C) 2011 Karel Zak <kzak@redhat.com>
#
# This file is part of util-linux.
#
TS_TOPDIR="$(dirname $0)/../.."
TS_DESC="defs"
. $TS_TOPDIR/functions.sh
ts_init "$*"
# list all items
$TS_HELPER_LOGINDEFS "$TS_SELF/logindefs.data" | sed 's:'$TS_SELF'/::g' >> $TS_OUTPUT
# search
$TS_HELPER_LOGINDEFS "$TS_SELF/logindefs.data" str STRING >> $TS_OUTPUT
$TS_HELPER_LOGINDEFS "$TS_SELF/logindefs.data" num NUMBER >> $TS_OUTPUT
$TS_HELPER_LOGINDEFS "$TS_SELF/logindefs.data" bool BOOLEAN >> $TS_OUTPUT
$TS_HELPER_LOGINDEFS "$TS_SELF/logindefs.data" str EMPTY >> $TS_OUTPUT
$TS_HELPER_LOGINDEFS "$TS_SELF/logindefs.data" str UNKNOWN >> $TS_OUTPUT
ts_finalize

View File

@ -0,0 +1,16 @@
#
# this is /etc/login.defs sample
#
HELLO_WORLD "hello world!"
STRING this_is_string # another comment
NUMBER 123456
BOOLEAN yEs
CRAZY1 = "this is crazy format"
CRAZY2=fooBar
CRAZY3 FoooBaaar
EMPTY
END "the is end"