* lib/parseopt.c: New file.

* lib/Makefile.am (libgraypam_la_SOURCES): Add parseopt.c
* lib/graypam.h (gray_parseopt, gray_wait_debug_fun): New
functions
(CNTL_DEBUG_LEV, CNTL_SET_DEBUG_LEV): Removed.
* lib/log.c (gray_wait_debug): New functions.
* pam_fshadow/pam_fshadow.c, pam_sql/pam_sql.c,
pam_regex/pam_regex.c, pam_log/pam_log.c: Use gray_parseopt for
command line parsing.



git-svn-id: file:///svnroot/pam-modules/trunk@67 56984be4-0537-0410-a56c-fcb268c96130
This commit is contained in:
Sergey Poznyakoff 2008-03-14 12:50:10 +00:00
parent 8600d3bc0e
commit 1128870a98
9 changed files with 359 additions and 186 deletions

View file

@ -1,3 +1,15 @@
2008-03-14 Sergey Poznyakoff <gray@gnu.org.ua>
* lib/parseopt.c: New file.
* lib/Makefile.am (libgraypam_la_SOURCES): Add parseopt.c
* lib/graypam.h (gray_parseopt, gray_wait_debug_fun): New
functions
(CNTL_DEBUG_LEV, CNTL_SET_DEBUG_LEV): Removed.
* lib/log.c (gray_wait_debug): New functions.
* pam_fshadow/pam_fshadow.c, pam_sql/pam_sql.c,
pam_regex/pam_regex.c, pam_log/pam_log.c: Use gray_parseopt for
command line parsing.
2008-03-13 Sergey Poznyakoff <gray@gnu.org.ua>
* configure.ac (PAM_COMMON_INCLUDES): Add -I${top_srcdir}/lib.

View file

@ -15,5 +15,8 @@
lib_LTLIBRARIES = libgraypam.la
libgraypam_la_SOURCES = log.c mem.c slist.c transform.c converse.c
libgraypam_la_SOURCES = log.c mem.c slist.c transform.c converse.c parseopt.c
noinst_HEADERS = graypam.h
noinst_PROGRAMS = parse
parse_LDADD = ./libgraypam.la -lpam
parse_LDFLAGS = -static

View file

@ -74,11 +74,12 @@
#define MAKE_STR(pamh, str, var) \
gray_make_str(pamh,str,#var,&var)
#define WAITDEBUG(arg) do { size_t line = __LINE__; \
#define WAITDEBUG(arg) do { \
size_t line = __LINE__; \
if ((arg)[0] == '=') \
gray_wait_debug(atoi((arg)+1), __FILE__, line); \
gray_wait_debug(atoi((arg)+1), __FILE__, line); \
else \
gray_wait_debug(0, __FILE__, line); \
gray_wait_debug(0, __FILE__, line); \
} while (0)
extern jmp_buf gray_pam_jmp;
@ -140,10 +141,36 @@ int gray_converse(pam_handle_t *pamh, int nargs,
#define CNTL_AUDIT 0x0002
#define CNTL_WAITDEBUG 0x0004
#define CNTL_DEBUG_LEV() (cntl_flags>>16)
#define CNTL_SET_DEBUG_LEV(cntl,n) (cntl |= ((n)<<16))
#define DEBUG(m,c) if (CNTL_DEBUG_LEV()>=(m)) _pam_debug c
#define DEBUG(m,c) if (debug_level>=(m)) _pam_debug c
#define AUDIT(c) if (cntl_flags&CNTL_AUDIT) _pam_debug c
enum pam_opt_type {
pam_opt_null,
pam_opt_bool,
pam_opt_bitmask,
pam_opt_bitmask_rev,
pam_opt_long,
pam_opt_string,
pam_opt_enum,
pam_opt_const
};
struct pam_opt {
const char *name;
size_t len;
enum pam_opt_type type;
void *data;
union {
long value;
const char **enumstr;
} v;
int (*func) (struct pam_opt *, const char *);
};
#define PAM_OPTSTR(s) #s, (sizeof(#s) - 1)
int gray_parseopt(struct pam_opt *opt, int argc, const char **argv);
int gray_wait_debug_fun (struct pam_opt *opt, const char *value);
#endif

View file

@ -67,8 +67,11 @@ gray_wait_debug(size_t interval, const char *file, size_t line)
#ifdef DEBUG_MODE
if (!interval)
interval = 3600;
gray_pam_log(LOG_CRIT, "WAITING FOR DEBUG AT %s:%d",
file, (unsigned long)line);
if (file)
gray_pam_log(LOG_CRIT, "WAITING FOR DEBUG AT %s:%d",
file, (unsigned long)line);
else
gray_pam_log(LOG_CRIT, "WAITING FOR DEBUG");
while (interval-- > 0)
sleep(1);
#else
@ -76,4 +79,21 @@ gray_wait_debug(size_t interval, const char *file, size_t line)
#endif
}
int
gray_wait_debug_fun (struct pam_opt *opt, const char *value)
{
char *s = "";
long n = value ? strtol(value, &s, 0) : 0;
if (*s) {
_pam_log(LOG_ERR,
"%s: %s is not a valid number",
opt->name, value);
return 1;
}
gray_wait_debug(0, NULL, 0);
return 0;
}

154
lib/parseopt.c Normal file
View file

@ -0,0 +1,154 @@
/* This file is part of pam-modules.
Copyright (C) 2008 Sergey Poznyakoff
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 3 of the License, or (at your
option) any later version.
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.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <graypam.h>
static struct pam_opt *
find_opt(struct pam_opt *opt, const char *str, const char **value)
{
size_t len = strlen(str);
int isbool;
if (len > 2 && memcmp(str, "no", 2) == 0) {
*value = NULL;
str += 2;
isbool = 1;
} else {
isbool = 0;
*value = str;
}
for (; opt->name; opt++) {
if (len >= opt->len
&& memcmp(opt->name, str, opt->len) == 0
&& (!isbool || opt->type == pam_opt_bool)) {
int eq = str[opt->len] == '=';
switch (opt->type) {
case pam_opt_long:
case pam_opt_string:
case pam_opt_enum:
if (!eq)
continue;
*value = str + opt->len + 1;
break;
case pam_opt_null:
if (eq)
*value = str + opt->len + 1;
else
*value = NULL;
break;
default:
if (eq)
continue;
break;
}
return opt;
}
}
return NULL;
}
int
find_value(const char **enumstr, const char *value)
{
int i;
for (i = 0; *enumstr; enumstr++, i++)
if (strcmp(*enumstr, value) == 0)
return i;
return -1;
}
int
gray_parseopt(struct pam_opt *opt, int argc, const char **argv)
{
long n;
char *s;
int rc = 0;
for (; argc-- > 0; ++argv) {
const char *value;
struct pam_opt *p = find_opt(opt, *argv, &value);
if (!p) {
_pam_log(LOG_ERR,
"%s: unknown option", *argv);
rc = 1;
continue;
}
switch (p->type) {
case pam_opt_long:
n = strtol(value, &s, 0);
if (*s) {
_pam_log(LOG_ERR,
"%s: %s is not a valid number",
p->name, value);
rc = 1;
continue;
}
*(long*)p->data = n;
break;
case pam_opt_const:
*(long*)p->data = p->v.value;
break;
case pam_opt_string:
*(const char**)p->data = value;
break;
case pam_opt_bool:
if (p->v.value) {
if (value)
*(int*)p->data |= p->v.value;
else
*(int*)p->data &= ~p->v.value;
} else
*(int*)p->data = value != NULL;
break;
case pam_opt_bitmask:
*(int*)p->data |= p->v.value;
break;
case pam_opt_bitmask_rev:
*(int*)p->data &= ~p->v.value;
break;
case pam_opt_enum:
n = find_value(p->v.enumstr, value);
if (n == -1) {
_pam_log(LOG_ERR,
"%s: invalid value %s",
p->name, value);
rc = 1;
continue;
}
*(int*)p->data = n;
break;
case pam_opt_null:
break;
}
if (p->func && p->func (p, value))
rc = 1;
}
return rc;
}

View file

@ -33,64 +33,59 @@ extern char *crypt(const char *, const char *);
#include <security/pam_modules.h>
#define CNTL_AUTHTOK 0x0010
#define CNTL_PASSWD 0x0020
#define CNTL_REGEX 0x0040
#define CNTL_REVERT_INDEX 0x0080
char *sysconfdir = SYSCONFDIR;
static int cntl_flags = 0;
static int cntl_flags = CNTL_PASSWD;
static long debug_level = 0;
static regex_t rexp;
const char *regex_str = NULL;
static const char *regex_str = NULL;
static int regex_flags = REG_EXTENDED;
static int username_index = 1;
static int domain_index = 2;
#define CNTL_AUTHTOK 0x0010
#define CNTL_NOPASSWD 0x0020
#define CNTL_REGEX 0x0040
struct pam_opt pam_opt[] = {
{ PAM_OPTSTR(debug), pam_opt_long, &debug_level },
{ PAM_OPTSTR(debug), pam_opt_const, &debug_level, 1 },
{ PAM_OPTSTR(audit), pam_opt_bitmask, &cntl_flags, CNTL_AUDIT },
{ PAM_OPTSTR(waitdebug), pam_opt_null, NULL, 0, gray_wait_debug_fun },
{ PAM_OPTSTR(use_authtok), pam_opt_bitmask, &cntl_flags,
CNTL_AUTHTOK },
{ PAM_OPTSTR(sysconfdir), pam_opt_string, &sysconfdir },
{ PAM_OPTSTR(regex), pam_opt_string, &regex_str },
{ PAM_OPTSTR(extended), pam_opt_bitmask, &regex_flags,
REG_EXTENDED },
{ PAM_OPTSTR(basic), pam_opt_bitmask_rev, &regex_flags,
REG_EXTENDED },
{ PAM_OPTSTR(icase), pam_opt_bitmask, &regex_flags,
REG_ICASE },
{ PAM_OPTSTR(ignore-case), pam_opt_bitmask, &regex_flags,
REG_ICASE },
{ PAM_OPTSTR(case), pam_opt_bitmask_rev, &regex_flags,
REG_ICASE },
{ PAM_OPTSTR(passwd), pam_opt_bool, &cntl_flags, CNTL_PASSWD },
{ PAM_OPTSTR(revert-index), pam_opt_bool, &cntl_flags,
CNTL_REVERT_INDEX },
{ NULL }
};
static int
_pam_parse(pam_handle_t *pamh, int argc, const char **argv)
{
int regex_flags = 0;
int retval = PAM_SUCCESS;
gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
if (gray_parseopt(pam_opt, argc, argv))
return PAM_AUTHINFO_UNAVAIL;
/* step through arguments */
for (cntl_flags = 0; argc-- > 0; ++argv) {
/* generic options */
if (!strncmp(*argv, "debug", 5)) {
cntl_flags |= CNTL_DEBUG;
if ((*argv)[5] == '=')
CNTL_SET_DEBUG_LEV(cntl_flags,
atoi(*argv + 6));
else
CNTL_SET_DEBUG_LEV(cntl_flags, 1);
} else if (!strncmp(*argv, "waitdebug", 9))
WAITDEBUG(*argv + 9);
else if (!strcmp(*argv,"use_authtok"))
cntl_flags |= CNTL_AUTHTOK;
else if (!strncmp(*argv, "sysconfdir=", 11))
sysconfdir = (char*) (*argv + 11);
else if (!strncmp(*argv, "regex=", 6))
regex_str = (*argv + 6);
else if (!strcmp(*argv, "basic"))
regex_flags &= ~REG_EXTENDED;
else if (!strcmp(*argv, "extended"))
regex_flags |= REG_EXTENDED;
else if (!strcmp(*argv, "icase")
|| !strcmp(*argv, "ignore-case"))
regex_flags |= REG_ICASE;
else if (!strcmp(*argv, "revert-index")) {
username_index = 2;
domain_index = 1;
} else if (!strcmp(*argv, "nopasswd"))
cntl_flags |= CNTL_NOPASSWD;
else
_pam_log(LOG_ERR,
"unknown option: %s", *argv);
if (cntl_flags & CNTL_REVERT_INDEX) {
username_index = 2;
domain_index = 1;
}
if (regex_str) {
int rc;
if (rc = regcomp(&rexp, regex_str, regex_flags)) {
@ -420,10 +415,10 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags,
return -2;
}
if (cntl_flags & CNTL_NOPASSWD)
retval = 0;
else
if (cntl_flags & CNTL_PASSWD)
retval = verify_user_acct(confdir, username, &pwstr);
else
retval = 0;
if (retval == PAM_SUCCESS) {
if (pwstr) {
if (strcmp(pwstr, crypt(password, pwstr)) == 0)

View file

@ -19,12 +19,14 @@
/* Command line parsing */
static int cntl_flags;
static long debug_level;
static int xargc;
static const char **xargv;
static int priority = LOG_INFO;
static int facility = LOG_AUTHPRIV;
static const char *syslog_tag =MODULE_NAME;
static const char *syslog_tag = MODULE_NAME;
static int do_open = 1;
struct keyword {
char *name;
@ -71,8 +73,8 @@ static struct keyword syslog_priority[] = {
{ NULL }
};
static void
parse_priority(const char *str)
static int
parse_priority(struct pam_opt *opt, const char *str)
{
int len;
struct keyword *kw;
@ -87,7 +89,7 @@ parse_priority(const char *str)
_pam_log(LOG_ERR,
"unknown syslog facility: %*.*s",
len, len, str);
return;
return 1;
}
facility = kw->code;
}
@ -98,52 +100,51 @@ parse_priority(const char *str)
if (!kw) {
_pam_log(LOG_ERR,
"unknown syslog priority: %s", str);
return;
return 1;
}
priority = kw->code;
}
return 0;
}
struct pam_opt pam_opt[] = {
{ PAM_OPTSTR(debug), pam_opt_long, &debug_level },
{ PAM_OPTSTR(debug), pam_opt_const, &debug_level, 1 },
{ PAM_OPTSTR(audit), pam_opt_bitmask, &cntl_flags, CNTL_AUDIT },
{ PAM_OPTSTR(waitdebug), pam_opt_null, NULL, 0, gray_wait_debug_fun },
{ PAM_OPTSTR(tag), pam_opt_string, &syslog_tag },
{ PAM_OPTSTR(pri), pam_opt_null, NULL, 0, parse_priority },
{ PAM_OPTSTR(open), pam_opt_bool, &do_open },
{ NULL }
};
static void
_pam_parse(pam_handle_t *pamh, int argc, const char **argv)
{
int ctrl = 0;
int dont_open = 0;
int i;
const char **targv;
/* Collect generic arguments */
for (; argc > 0; argv++, argc--) {
if (!strncmp(*argv, "-debug", 6)) {
ctrl |= CNTL_DEBUG;
if ((*argv)[6] == '=')
CNTL_SET_DEBUG_LEV(ctrl, atoi(*argv + 7));
else
CNTL_SET_DEBUG_LEV(ctrl, 1);
} else if (!strcmp(*argv, "-audit"))
ctrl |= CNTL_AUDIT;
else if (!strncmp(*argv, "-waitdebug", 10))
WAITDEBUG(*argv + 10);
else if (!strncmp(*argv, "-tag=", 5))
syslog_tag = *argv + 5;
else if (!strncmp(*argv, "-pri=", 5))
parse_priority(*argv + 5);
else if (!strcmp(*argv, "-no-open"))
dont_open = 1;
else if (!strcmp(*argv, "--"))
break;
else if (**argv == '-')
_pam_log(LOG_ERR,
"unknown option: %s", *argv);
else
gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
targv = gray_malloc(argc * sizeof (targv[0]));
for (i = 0; i < argc; i++) {
if (argv[i][0] == '-') {
if (argv[i][1] == '-' && argv[i][2] == 0)
break;
targv[i] = argv[i] + 1;
} else
break;
}
/* Save the format variables */
xargc = argc;
xargv = argv;
gray_parseopt(pam_opt, i, targv);
free(targv);
cntl_flags = ctrl;
xargc = argc - i;
xargv = argv + i;
gray_log_init(dont_open, syslog_tag, facility);
closelog();
gray_log_init(!do_open, syslog_tag, facility);
}
static struct keyword vartab[] = {
@ -312,24 +313,28 @@ echo(pam_handle_t *pamh, const char *prefix, int argc, const char **argv)
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
gray_pam_init(PAM_IGNORE);
return echo(pamh, __FUNCTION__, argc, argv);
}
PAM_EXTERN int
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
gray_pam_init(PAM_IGNORE);
return echo(pamh, __FUNCTION__, argc, argv);
}
PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc,const char **argv)
{
gray_pam_init(PAM_IGNORE);
return echo(pamh, __FUNCTION__, argc, argv);
}
PAM_EXTERN int
pam_sm_acct_mgmt (pam_handle_t *pamh, int flags, int argc, const char **argv)
{
gray_pam_init(PAM_IGNORE);
return echo(pamh, __FUNCTION__, argc, argv);
}
@ -337,6 +342,7 @@ PAM_EXTERN int
pam_sm_open_session (pam_handle_t *pamh, int flags, int argc,
const char **argv)
{
gray_pam_init(PAM_IGNORE);
return echo(pamh, __FUNCTION__, argc, argv);
}
@ -344,6 +350,7 @@ PAM_EXTERN int
pam_sm_close_session (pam_handle_t *pamh, int flags, int argc,
const char **argv)
{
gray_pam_init(PAM_IGNORE);
return echo(pamh, __FUNCTION__, argc, argv);
}

View file

@ -39,81 +39,54 @@
#include <security/pam_modules.h>
#define CNTL_AUTHTOK 0x0010
#define CNTL_REGEX_FLAGS 0x0012
#define SENSE_ALLOW 0
#define SENSE_DENY 1
const char *sense_choice[] = { "allow", "deny", NULL };
static int sense;
static int cntl_flags;
static long debug_level;
static const char *regex = NULL;
static int regex_flags = REG_NOSUB;
static int regex_flags = REG_NOSUB|REG_EXTENDED;
static const char *transform = NULL;
static const char *user_name;
struct pam_opt pam_opt[] = {
{ PAM_OPTSTR(debug), pam_opt_long, &debug_level },
{ PAM_OPTSTR(debug), pam_opt_const, &debug_level, 1 },
{ PAM_OPTSTR(audit), pam_opt_bitmask, &cntl_flags, CNTL_AUDIT },
{ PAM_OPTSTR(waitdebug), pam_opt_null, NULL, 0, gray_wait_debug_fun },
{ PAM_OPTSTR(use_authtok), pam_opt_bitmask, &cntl_flags,
CNTL_AUTHTOK },
{ PAM_OPTSTR(sense), pam_opt_enum, &sense, sense_choice },
{ PAM_OPTSTR(transform), pam_opt_string, &transform },
{ PAM_OPTSTR(user_name), pam_opt_string, &user_name },
{ PAM_OPTSTR(regex), pam_opt_string, &regex },
{ PAM_OPTSTR(extended), pam_opt_bitmask, &regex_flags,
REG_EXTENDED },
{ PAM_OPTSTR(basic), pam_opt_bitmask_rev, &regex_flags,
REG_EXTENDED },
{ PAM_OPTSTR(icase), pam_opt_bitmask, &regex_flags,
REG_ICASE },
{ PAM_OPTSTR(ignore-case), pam_opt_bitmask, &regex_flags,
REG_ICASE },
{ PAM_OPTSTR(case), pam_opt_bitmask_rev, &regex_flags,
REG_ICASE },
{ NULL }
};
static void
_pam_parse(pam_handle_t *pamh, int argc, const char **argv)
{
int ctrl = 0;
gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
/* step through arguments */
for (; argc-- > 0; ++argv) {
/* generic options */
if (!strncmp(*argv, "debug", 5)) {
ctrl |= CNTL_DEBUG;
if ((*argv)[5] == '=')
CNTL_SET_DEBUG_LEV(ctrl, atoi(*argv + 6));
else
CNTL_SET_DEBUG_LEV(ctrl, 1);
} else if (!strcmp(*argv, "audit"))
ctrl |= CNTL_AUDIT;
else if (!strncmp(*argv, "waitdebug", 9))
WAITDEBUG(*argv + 9);
else if (!strcmp(*argv, "use_authtok"))
ctrl |= CNTL_AUTHTOK;
else if (!strncmp(*argv, "sense=", 6)) {
if (strcmp(*argv + 6, "deny") == 0)
sense = SENSE_DENY;
else if (strcmp(*argv + 6, "allow") == 0)
sense = SENSE_ALLOW;
else
_pam_log(LOG_ERR,"unknown sense value: %s",
*argv + 6);
} else if (!strncmp(*argv, "transform=", 10))
transform = *argv + 10;
else if (!strncmp(*argv, "user=",5))
user_name = *argv + 5;
else if (!strncmp(*argv, "regex=", 6))
regex = *argv + 6;
else if (!strcmp(*argv, "extended")) {
regex_flags |= REG_EXTENDED;
ctrl |= CNTL_REGEX_FLAGS;
} else if (!strcmp(*argv, "basic")) {
regex_flags &= ~REG_EXTENDED;
ctrl |= CNTL_REGEX_FLAGS;
} else if (!strcmp(*argv, "icase")
|| !strcmp(*argv, "ignore-case")) {
regex_flags |= REG_ICASE;
ctrl |= CNTL_REGEX_FLAGS;
} else if (!strcmp(*argv, "case")) {
regex_flags &= ~REG_ICASE;
ctrl |= CNTL_REGEX_FLAGS;
} else {
_pam_log(LOG_ERR,
"unknown option: %s", *argv);
}
}
if (!regex)
_pam_log(LOG_ERR, "regex not specified");
gray_parseopt(pam_opt, argc, argv);
if (!regex && !transform)
_pam_log(LOG_ERR, "neither regex nor transform are specified");
if (user_name && transform)
_pam_log(LOG_ERR, "Both `user' and `transform' are given");
if (!(ctrl & CNTL_REGEX_FLAGS))
regex_flags |= REG_EXTENDED;
cntl_flags = ctrl;
}
/*
@ -141,9 +114,6 @@ pam_sm_authenticate(pam_handle_t *pamh,
DEBUG(100,("enter pam_sm_authenticate"));
if (!regex)
return PAM_AUTHINFO_UNAVAIL;
gray_pam_init(PAM_AUTHINFO_UNAVAIL);
/*

View file

@ -36,40 +36,25 @@ static int verify_user_pass(const char *username, const char *password);
#define CNTL_AUTHTOK 0x0010
static int cntl_flags;
static long debug_level;
char *config_file = SYSCONFDIR "/pam_sql.conf";
struct pam_opt pam_opt[] = {
{ PAM_OPTSTR(debug), pam_opt_long, &debug_level },
{ PAM_OPTSTR(debug), pam_opt_const, &debug_level, 1 },
{ PAM_OPTSTR(audit), pam_opt_bitmask, &cntl_flags, CNTL_AUDIT },
{ PAM_OPTSTR(waitdebug), pam_opt_null, NULL, 0, gray_wait_debug_fun },
{ PAM_OPTSTR(use_authtok), pam_opt_bitmask, &cntl_flags,
CNTL_AUTHTOK },
{ PAM_OPTSTR(config_file), pam_opt_string, &config_file },
{ NULL }
};
static void
_pam_parse(int argc, const char **argv)
{
int ctrl=0;
gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
/* step through arguments */
for (ctrl=0; argc-- > 0; ++argv) {
/* generic options */
if (!strncmp(*argv,"debug",5)) {
ctrl |= CNTL_DEBUG;
if ((*argv)[5] == '=')
CNTL_SET_DEBUG_LEV(ctrl,atoi(*argv+6));
else
CNTL_SET_DEBUG_LEV(ctrl,1);
} else if (!strcmp(*argv, "audit"))
ctrl |= CNTL_AUDIT;
else if (!strncmp(*argv, "waitdebug", 9))
WAITDEBUG(*argv + 9);
else if (!strcmp(*argv,"use_authtok"))
ctrl |= CNTL_AUTHTOK;
else if (!strncmp(*argv, "config=", 7))
config_file = (char*) (*argv + 7);
else {
_pam_log(LOG_ERR,"unknown option: %s",
*argv);
}
}
cntl_flags = ctrl;
gray_parseopt(pam_opt, argc, argv);
}