%{ /* ----------------------------------------------------------------------- * * * nss_parser.y - nsswitch parser. * * Copyright 2006 Ian Kent * * 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, Inc., 675 Mass Ave, Cambridge MA 02139, * USA; either version 2 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. * * ----------------------------------------------------------------------- */ #include #include #include #include #include #include "automount.h" #include "nsswitch.h" #include "nss_parse.tab.h" static pthread_mutex_t parse_mutex = PTHREAD_MUTEX_INITIALIZER; static struct list_head *nss_list; static struct nss_source *src; struct nss_action act[NSS_STATUS_MAX]; #define YYDEBUG 0 #ifndef YYENABLE_NLS #define YYENABLE_NLS 0 #endif #ifndef YYLTYPE_IS_TRIVIAL #define YYLTYPE_IS_TRIVIAL 0 #endif unsigned int nss_automount_found; extern int nss_lineno; extern int nss_lex(void); extern FILE *nss_in; static int nss_ignore(const char *s); static int nss_error(const char *s); %} %union { char strval[128]; } %token LBRACKET RBRACKET EQUAL BANG NL %token SOURCE %token STATUS %token ACTION %start file %% file: { #if YYDEBUG != 0 nss_debug = YYDEBUG; #endif } sources NL | /* empty */ ; sources: nss_source | nss_source sources ; nss_source: SOURCE { if (!strcmp($1, "files") || !strcmp($1, "yp") || !strcmp($1, "nis") || !strcmp($1, "ldap") || !strcmp($1, "nisplus") || !strcmp($1, "hesiod") || !strcmp($1, "sss")) src = add_source(nss_list, $1); else nss_ignore($1); } | SOURCE LBRACKET status_exp_list RBRACKET { enum nsswitch_status a; if (!strcmp($1, "files") || !strcmp($1, "yp") || !strcmp($1, "nis") || !strcmp($1, "ldap") || !strcmp($1, "nisplus") || !strcmp($1, "hesiod") || !strcmp($1, "sss")) { src = add_source(nss_list, $1); for (a = 0; a < NSS_STATUS_MAX; a++) { if (act[a].action != NSS_ACTION_UNKNOWN) { src->action[a].action = act[a].action; src->action[a].negated = act[a].negated; } } } else nss_ignore($1); } | SOURCE LBRACKET status_exp_list SOURCE { nss_error("missing close bracket"); YYABORT; } | SOURCE LBRACKET status_exp_list NL { nss_error("missing close bracket"); YYABORT; } | SOURCE LBRACKET SOURCE { nss_error($3); YYABORT; } | error SOURCE { nss_error($2); YYABORT; }; status_exp_list: status_exp | status_exp status_exp_list status_exp: STATUS EQUAL ACTION { set_action(act, $1, $3, 0); } | BANG STATUS EQUAL ACTION { set_action(act, $2, $4, 1); } | STATUS EQUAL SOURCE {nss_error($3); YYABORT; } | STATUS SOURCE {nss_error($2); YYABORT; } | BANG STATUS EQUAL SOURCE {nss_error($4); YYABORT; } | BANG STATUS SOURCE {nss_error($3); YYABORT; } | BANG SOURCE {nss_error($2); YYABORT; }; %% static int nss_ignore(const char *s) { logmsg("ignored unsupported autofs nsswitch source \"%s\"", s); return(0); } static int nss_error(const char *s) { logmsg("syntax error in nsswitch config near [ %s ]\n", s); return(0); } static void parse_mutex_lock(void) { int status = pthread_mutex_lock(&parse_mutex); if (status) fatal(status); return; } static void parse_mutex_unlock(void *arg) { int status = pthread_mutex_unlock(&parse_mutex); if (status) fatal(status); return; } static void parse_close_nsswitch(void *arg) { FILE *nsswitch = (FILE *) arg; fclose(nsswitch); return; } int nsswitch_parse(struct list_head *list) { FILE *nsswitch; int status; nsswitch = open_fopen_r(NSSWITCH_FILE); if (!nsswitch) { logerr("couldn't open %s", NSSWITCH_FILE); return 1; } pthread_cleanup_push(parse_close_nsswitch, nsswitch); parse_mutex_lock(); pthread_cleanup_push(parse_mutex_unlock, NULL); nss_in = nsswitch; nss_automount_found = 0; nss_list = list; status = nss_parse(); nss_list = NULL; /* No "automount" nsswitch entry, use "files" */ if (!nss_automount_found) if (add_source(list, "files")) status = 0; pthread_cleanup_pop(1); pthread_cleanup_pop(1); if (status) return 1; return 0; }