/***************************************************************** ** ** lg_mesg (level, fmt, ...) ** ** Write a given message to the error log file and counts ** all messages written with an level greater than LOG_ERR. ** ** All messages will be on one line in the logfile, so it's ** not necessary to add an '\n' to the message. ** ** To call this function before an elog_open() is called is ** useless! ** *****************************************************************/ void lg_mesg (int priority, char *fmt, ...) { va_list ap; struct timeval tv; struct tm *t; char format[256]; assert (fmt != NULL); assert (priority >= LG_DEBUG && priority <= LG_FATAL); format[0] ='\0'; dbg_val3 ("syslog = %d prio = %d >= sysmin = %d\n", lg_syslogging, priority, lg_minsyslevel); if ( lg_syslogging && priority >= lg_minsyslevel ) { #if defined (LOG_WITH_LEVEL) && LOG_WITH_LEVEL snprintf (format, sizeof (format), "%s: %s", lg_lvl2str(priority), fmt); fmt = format; #endif va_start(ap, fmt); vsyslog (lg_lvl2syslog (priority), fmt, ap); va_end(ap); } dbg_val3 ("filelg = %d prio = %d >= filmin = %d\n", lg_fp!=NULL, priority, lg_minfilelevel); if ( lg_fp && priority >= lg_minfilelevel ) { #if defined (LOG_WITH_TIMESTAMP) && LOG_WITH_TIMESTAMP gettimeofday (&tv, NULL); t = localtime ((time_t *) &tv.tv_sec); fprintf (lg_fp, "%04d-%02d-%02d ", t->tm_year+1900, t->tm_mon+1, t->tm_mday); fprintf (lg_fp, "%02d:%02d:%02d.%03ld: ", t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000); #endif #if defined (LOG_WITH_PROGNAME) && LOG_WITH_PROGNAME if ( lg_progname ) fprintf (lg_fp, "%s: ", lg_progname); #endif #if defined (LOG_WITH_LEVEL) && LOG_WITH_LEVEL if ( fmt != format ) /* level is not in fmt string */ fprintf (lg_fp, "%s: ", lg_lvl2str(priority)); #endif va_start(ap, fmt); vfprintf (lg_fp, fmt, ap); va_end(ap); fprintf (lg_fp, "\n"); } if ( priority >= LG_ERROR ) lg_errcnt++; }
/***************************************************************** ** reload a zone via "rndc" *****************************************************************/ int reload_zone (const char *domain, const zconf_t *z) { char cmdline[254+1]; char str[254+1]; FILE *fp; assert (z != NULL); dbg_val3 ("reload_zone %d :%s: :%s:\n", z->verbosity, domain, z->view); if ( z->view ) snprintf (str, sizeof (str), "\"%s\" in view \"%s\"", domain, z->view); else snprintf (str, sizeof (str), "\"%s\"", domain); lg_mesg (LG_NOTICE, "%s: reload triggered", str); verbmesg (1, z, "\tReload zone %s\n", str); if ( z->view ) snprintf (cmdline, sizeof (cmdline), "%s reload %s IN %s", RELOADCMD, domain, z->view); else snprintf (cmdline, sizeof (cmdline), "%s reload %s", RELOADCMD, domain); *str = '\0'; if ( z->noexec == 0 ) { verbmesg (2, z, "\t Run cmd \"%s\"\n", cmdline); if ( (fp = popen (cmdline, "r")) == NULL || fgets (str, sizeof str, fp) == NULL ) return -1; pclose (fp); verbmesg (2, z, "\t rndc reload return: \"%s\"\n", str_chop (str, '\n')); } return 0; }
/***************************************************************** ** ** parse_keyconf (const char *filename, dir, dirsize, int (*func) ()) ** ** Very dumb named.conf parser. ** - For every key definition "func (keyname, algo, secret)" will be called ** *****************************************************************/ static int parse_keyconf (const char *filename, char *dir, size_t dirsize, tsigkey_t *k, const char *lookup) { FILE *fp; int ret; int tok; char path[511+1]; char strval[4095+1]; char key[255+1]; char alg[31+1]; char secret[255+1]; dbg_val ("parse_keyconf: parsing file \"%s\" \n", filename); assert (filename != NULL); assert (dir != NULL && dirsize != 0); assert ( k != NULL); if ( (fp = fopen (filename, "r")) == NULL ) return -1; ret = 0; while ( (tok = gettok (fp, strval, sizeof strval)) != EOF ) { if ( tok > 0 && tok < 256 ) { fprintf (stderr, "parse_keyconf: token found with value %-10d: %c\n", tok, tok); } else if ( tok == TOK_DIR ) { if ( gettok (fp, strval, sizeof (strval)) == TOK_STRING ) { dbg_val2 ("parse_namedconf: directory found \"%s\" (dir is %s)\n", strval, dir); if ( *strval != '/' && *dir ) snprintf (path, sizeof (path), "%s/%s", dir, strval); else snprintf (path, sizeof (path), "%s", strval); snprintf (dir, dirsize, "%s", path); dbg_val ("parse_namedconf: new dir \"%s\" \n", dir); } } else if ( tok == TOK_INCLUDE ) { if ( gettok (fp, strval, sizeof (strval)) == TOK_STRING ) { if ( *strval != '/' && *dir ) snprintf (path, sizeof (path), "%s/%s", dir, strval); else snprintf (path, sizeof (path), "%s", strval); if ( (ret = parse_keyconf (path, dir, dirsize, k, lookup)) != 0 ) return ret; } else { fprintf (stderr, "parse_keyconf: need a filename after \"include\"!\n"); } } else if ( tok == TOK_KEY ) { int nrtok; dbg_val0 ("parse_keyconf: new key found \n"); if ( gettok (fp, strval, sizeof (strval)) != TOK_STRING ) continue; snprintf (key, sizeof key, "%s", strval); /* store the name of the key */ dbg_val ("parse_keyconf: keyname \"%s\" \n", key); nrtok = 0; while ( nrtok < 2 && (tok = gettok (fp, strval, sizeof (strval))) ) { if ( tok == TOK_ALG ) { switch ( gettok (fp, strval, sizeof (strval)) ) { case TOK_HMAC_MD5: case TOK_HMAC_SHA1: case TOK_HMAC_SHA224: case TOK_HMAC_SHA256: case TOK_HMAC_SHA384: case TOK_HMAC_SHA512: snprintf (alg, sizeof alg, "%s", strval); /* this is the algorithm */ break; default: *alg = '\0'; continue; } } else if ( tok == TOK_SECRET ) { if ( gettok (fp, strval, sizeof (strval)) != TOK_STRING ) break; snprintf (secret, sizeof secret, "%s", strval); /* this is the secret */ } nrtok++; } dbg_val5 ("dir %s key %s alg %s secret %s lookup \"%s\"\n", dir, key, alg, secret, lookup ? lookup: "NULL"); if ( lookup == NULL || lookup[0] == '\0' || strcmp (key, lookup) == 0 ) { snprintf (k->name, sizeof (k->name), "%s", key); snprintf (k->algo, sizeof (k->algo), "%s", alg); snprintf (k->secret, sizeof (k->secret), "%s", secret); ret = 1; break; } } else dbg_val3 ("%-10s(%d): %s\n", tok2str(tok), tok, strval); } fclose (fp); dbg_val2 ("parse_keyconf: leaving file \"%s\" ret = %d \n", filename, ret); return ret; }
/***************************************************************** ** parsezonefile () ** parse the BIND zone file 'file' and store the minimum and ** maximum ttl value in the corresponding parameter. ** if keydbfile is set, check if this file is already include. ** if inclfiles is not NULL store a list of included files names ** in it. ** return 0 if keydbfile is not included ** return 1 if keydbfile is included ** return -1 on error *****************************************************************/ int parsezonefile (const char *file, long *pminttl, long *pmaxttl, const char *keydbfile, char *inclfiles, size_t *plen) { FILE *infp; int len; int lnr; long ttl; int multi_line_rr; int keydbfilefound; char buf[1024]; const char *p; assert (file != NULL); assert (pminttl != NULL); assert (pmaxttl != NULL); dbg_val4 ("parsezonefile (\"%s\", %ld, %ld, \"%s\")\n", file, *pminttl, *pmaxttl, keydbfile); if ( (infp = fopen (file, "r")) == NULL ) { error ("parsezonefile: couldn't open file \"%s\" for input\n", file); return -1; } lnr = 0; keydbfilefound = 0; multi_line_rr = 0; while ( fgets (buf, sizeof buf, infp) != NULL ) { len = strlen (buf); if ( buf[len-1] != '\n' ) /* line too long ? */ fprintf (stderr, "line too long\n"); lnr++; p = buf; if ( multi_line_rr ) /* skip line if it's part of a multiline rr */ { is_multiline_rr (&multi_line_rr, p); continue; } if ( *p == '$' ) /* special directive ? */ { if ( strncmp (p+1, "TTL", 3) == 0 ) /* $TTL ? */ { ttl = get_ttl (p+4); dbg_val3 ("%s:%d:ttl %ld\n", file, lnr, ttl); setminmax (pminttl, ttl, pmaxttl); } else if ( strncmp (p+1, "INCLUDE", 7) == 0 ) /* $INCLUDE ? */ { char fname[30+1]; sscanf (p+9, "%30s", fname); dbg_val ("$INCLUDE directive for file \"%s\" found\n", fname); if ( strcmp (fname, keydbfile) == 0 ) keydbfilefound = 1; else { if ( inclfiles && plen ) { len = snprintf (inclfiles, *plen, ",%s", fname); if ( *plen <= len ) /* no space left in include file string */ return keydbfilefound; inclfiles += len; *plen -= len; } int ret = parsezonefile (fname, pminttl, pmaxttl, keydbfile, inclfiles, plen); if ( ret ) /* keydb found or read error ? */ keydbfilefound = ret; } } } else if ( !isspace (*p) ) /* label ? */ p = skiplabel (p); p = skipws (p); if ( *p == ';' ) /* skip line if it's a comment line */ continue; /* skip class (hesiod is not supported now) */ if ( (toupper (*p) == 'I' && toupper (p[1]) == 'N') || (toupper (*p) == 'C' && toupper (p[1]) == 'H') ) p += 2; p = skipws (p); if ( isdigit (*p) ) /* ttl ? */ { ttl = get_ttl (p); dbg_val3 ("%s:%d:ttl %ld\n", file, lnr, ttl); setminmax (pminttl, ttl, pmaxttl); } /* check the rest of the line if it's the beginning of a multi_line_rr */ is_multiline_rr (&multi_line_rr, p); } if ( file ) fclose (infp); dbg_val5 ("parsezonefile (\"%s\", %ld, %ld, \"%s\") ==> %d\n", file, *pminttl, *pmaxttl, keydbfile, keydbfilefound); return keydbfilefound; }
/***************************************************************** ** ** parse_namedconf (const char *filename, chroot_dir, dir, dirsize, int (*func) ()) ** ** Very dumb named.conf parser. ** - In a zone declaration the _first_ keyword MUST be "type" ** - For every master zone "func (directory, zone, filename)" will be called ** *****************************************************************/ int parse_namedconf (const char *filename, const char *chroot_dir, char *dir, size_t dirsize, int (*func) ()) { FILE *fp; int tok; char path[511+1]; #if 1 /* this is potentialy too small for key data, but we don't need the keys... */ char strval[255+1]; #else char strval[4095+1]; #endif char view[255+1]; char zone[255+1]; char zonefile[255+1]; dbg_val ("parse_namedconf: parsing file \"%s\" \n", filename); assert (filename != NULL); assert (dir != NULL && dirsize != 0); assert (func != NULL); view[0] = '\0'; if ( (fp = fopen (filename, "r")) == NULL ) return 0; while ( (tok = gettok (fp, strval, sizeof strval)) != EOF ) { if ( tok > 0 && tok < 256 ) { error ("parse_namedconf: token found with value %-10d: %c\n", tok, tok); lg_mesg (LG_ERROR, "parse_namedconf: token found with value %-10d: %c", tok, tok); } else if ( tok == TOK_DIR ) { if ( gettok (fp, strval, sizeof (strval)) == TOK_STRING ) { dbg_val2 ("parse_namedconf: directory found \"%s\" (dir is %s)\n", strval, dir); if ( *strval != '/' && *dir ) snprintf (path, sizeof (path), "%s/%s", dir, strval); else snprintf (path, sizeof (path), "%s", strval); /* prepend chroot directory (do it only once) */ if ( chroot_dir && *chroot_dir ) { snprintf (dir, dirsize, "%s%s%s", chroot_dir, *path == '/' ? "": "/", path); chroot_dir = NULL; } else snprintf (dir, dirsize, "%s", path); dbg_val ("parse_namedconf: new dir \"%s\" \n", dir); } } else if ( tok == TOK_INCLUDE ) { if ( gettok (fp, strval, sizeof (strval)) == TOK_STRING ) { if ( *strval != '/' && *dir ) snprintf (path, sizeof (path), "%s/%s", dir, strval); else snprintf (path, sizeof (path), "%s", strval); if ( !parse_namedconf (path, chroot_dir, dir, dirsize, func) ) return 0; } else { error ("parse_namedconf: need a filename after \"include\"!\n"); lg_mesg (LG_ERROR, "parse_namedconf: need a filename after \"include\"!"); } } else if ( tok == TOK_VIEW ) { if ( gettok (fp, strval, sizeof (strval)) != TOK_STRING ) continue; snprintf (view, sizeof view, "%s", strval); /* store the name of the view */ } else if ( tok == TOK_ZONE ) { if ( gettok (fp, strval, sizeof (strval)) != TOK_STRING ) continue; snprintf (zone, sizeof zone, "%s", strval); /* store the name of the zone */ if ( gettok (fp, strval, sizeof (strval)) != TOK_MASTER ) continue; if ( gettok (fp, strval, sizeof (strval)) != TOK_FILE ) continue; if ( gettok (fp, strval, sizeof (strval)) != TOK_STRING ) continue; snprintf (zonefile, sizeof zonefile, "%s", strval); /* this is the filename */ dbg_val4 ("dir %s view %s zone %s file %s\n", dir, view, zone, zonefile); (*func) (dir, view, zone, zonefile); } else dbg_val3 ("%-10s(%d): %s\n", tok2str(tok), tok, strval); } fclose (fp); return 1; }