Back to index

glibc  2.9
Defines | Functions
hesiod.c File Reference
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hesiod.h"
#include "hesiod_p.h"

Go to the source code of this file.

Defines

#define _PATH_HESIOD_CONF   "/etc/hesiod.conf"

Functions

int hesiod_init (void **context)
void hesiod_end (void *context)
char * hesiod_to_bind (void *context, const char *name, const char *type)
char ** hesiod_resolve (void *context, const char *name, const char *type)
void hesiod_free_list (void *context, char **list)
static int parse_config_file (struct hesiod_p *ctx, const char *filename)
static char ** get_txt_records (struct hesiod_p *ctx, int class, const char *name)
static int init (struct hesiod_p *ctx)
struct __res_state__hesiod_res_get (void *context)
void __hesiod_res_set (void *context, struct __res_state *res, void(*free_res)(void *))

Define Documentation

#define _PATH_HESIOD_CONF   "/etc/hesiod.conf"

Definition at line 51 of file hesiod.c.


Function Documentation

struct __res_state* __hesiod_res_get ( void *  context) [read]

Definition at line 469 of file hesiod.c.

                                {
       struct hesiod_p *ctx = context;

       if (!ctx->res) {
              struct __res_state *res;
              res = (struct __res_state *)calloc(1, sizeof *res);
              if (res == NULL)
                     return (NULL);
              __hesiod_res_set(ctx, res, free);
       }

       return (ctx->res);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void __hesiod_res_set ( void *  context,
struct __res_state res,
void(*)(void *)  free_res 
)

Definition at line 484 of file hesiod.c.

                                          {
       struct hesiod_p *ctx = context;

       if (ctx->res && ctx->free_res) {
              res_nclose(ctx->res);
              (*ctx->free_res)(ctx->res);
       }

       ctx->res = res;
       ctx->free_res = free_res;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char ** get_txt_records ( struct hesiod_p ctx,
int  class,
const char *  name 
) [static]

Definition at line 351 of file hesiod.c.

                                                                   {
       struct {
              int type;            /* RR type */
              int class;           /* RR class */
              int dlen;            /* len of data section */
              u_char *data;        /* pointer to data */
       } rr;
       HEADER *hp;
       u_char qbuf[MAX_HESRESP], abuf[MAX_HESRESP];
       u_char *cp, *erdata, *eom;
       char *dst, *edst, **list;
       int ancount, qdcount;
       int i, j, n, skip;

       /*
        * Construct the query and send it.
        */
       n = res_nmkquery(ctx->res, QUERY, name, class, T_TXT, NULL, 0,
                      NULL, qbuf, MAX_HESRESP);
       if (n < 0) {
              __set_errno(EMSGSIZE);
              return (NULL);
       }
       n = res_nsend(ctx->res, qbuf, n, abuf, MAX_HESRESP);
       if (n < 0) {
              __set_errno(ECONNREFUSED);
              return (NULL);
       }
       if (n < HFIXEDSZ) {
              __set_errno(EMSGSIZE);
              return (NULL);
       }

       /*
        * OK, parse the result.
        */
       hp = (HEADER *) abuf;
       ancount = ntohs(hp->ancount);
       qdcount = ntohs(hp->qdcount);
       cp = abuf + sizeof(HEADER);
       eom = abuf + n;

       /* Skip query, trying to get to the answer section which follows. */
       for (i = 0; i < qdcount; i++) {
              skip = dn_skipname(cp, eom);
              if (skip < 0 || cp + skip + QFIXEDSZ > eom) {
                     __set_errno(EMSGSIZE);
                     return (NULL);
              }
              cp += skip + QFIXEDSZ;
       }

       list = malloc((ancount + 1) * sizeof(char *));
       if (!list)
              return (NULL);
       j = 0;
       for (i = 0; i < ancount; i++) {
              skip = dn_skipname(cp, eom);
              if (skip < 0) {
                     __set_errno(EMSGSIZE);
                     goto cleanup;
              }
              cp += skip;
              if (cp + 3 * INT16SZ + INT32SZ > eom) {
                     __set_errno(EMSGSIZE);
                     goto cleanup;
              }
              rr.type = ns_get16(cp);
              cp += INT16SZ;
              rr.class = ns_get16(cp);
              cp += INT16SZ + INT32SZ;    /* skip the ttl, too */
              rr.dlen = ns_get16(cp);
              cp += INT16SZ;
              if (cp + rr.dlen > eom) {
                     __set_errno(EMSGSIZE);
                     goto cleanup;
              }
              rr.data = cp;
              cp += rr.dlen;
              if (rr.class != class || rr.type != T_TXT)
                     continue;
              if (!(list[j] = malloc(rr.dlen)))
                     goto cleanup;
              dst = list[j++];
              edst = dst + rr.dlen;
              erdata = rr.data + rr.dlen;
              cp = rr.data;
              while (cp < erdata) {
                     n = (unsigned char) *cp++;
                     if (cp + n > eom || dst + n > edst) {
                            __set_errno(EMSGSIZE);
                            goto cleanup;
                     }
                     memcpy(dst, cp, n);
                     cp += n;
                     dst += n;
              }
              if (cp != erdata) {
                     __set_errno(EMSGSIZE);
                     goto cleanup;
              }
              *dst = '\0';
       }
       list[j] = NULL;
       if (j == 0) {
              __set_errno(ENOENT);
              goto cleanup;
       }
       return (list);

 cleanup:
       for (i = 0; i < j; i++)
              free(list[i]);
       free(list);
       return (NULL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void hesiod_end ( void *  context)

Definition at line 151 of file hesiod.c.

                          {
       struct hesiod_p *ctx = (struct hesiod_p *) context;
       int save_errno = errno;

       if (ctx->res)
              res_nclose(ctx->res);
       free(ctx->RHS);
       free(ctx->LHS);
       if (ctx->res && ctx->free_res)
              (*ctx->free_res)(ctx->res);
       free(ctx);
       __set_errno(save_errno);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void hesiod_free_list ( void *  context,
char **  list 
)

Definition at line 251 of file hesiod.c.

                                             {
       char **p;

       for (p = list; *p; p++)
              free(*p);
       free(list);
}

Here is the caller graph for this function:

int hesiod_init ( void **  context)

Definition at line 74 of file hesiod.c.

                            {
       struct hesiod_p *ctx;
       const char *configname;
       char *cp;

       ctx = malloc(sizeof(struct hesiod_p));
       if (ctx == 0)
              return (-1);

       ctx->LHS = NULL;
       ctx->RHS = NULL;
       ctx->res = NULL;
       /* Set default query classes. */
       ctx->classes[0] = C_IN;
       ctx->classes[1] = C_HS;

       configname = __secure_getenv("HESIOD_CONFIG");
       if (!configname)
         configname = _PATH_HESIOD_CONF;
       if (parse_config_file(ctx, configname) < 0) {
#ifdef DEF_RHS
              /*
               * Use compiled in defaults.
               */
              ctx->LHS = malloc(strlen(DEF_LHS)+1);
              ctx->RHS = malloc(strlen(DEF_RHS)+1);
              if (ctx->LHS == 0 || ctx->RHS == 0)
                     goto cleanup;
              strcpy(ctx->LHS, DEF_LHS);
              strcpy(ctx->RHS, DEF_RHS);
#else
              goto cleanup;
#endif
       }
       /*
        * The default RHS can be overridden by an environment
        * variable.
        */
       if ((cp = __secure_getenv("HES_DOMAIN")) != NULL) {
              free(ctx->RHS);
              ctx->RHS = malloc(strlen(cp)+2);
              if (!ctx->RHS)
                     goto cleanup;
              if (cp[0] == '.')
                     strcpy(ctx->RHS, cp);
              else {
                     ctx->RHS[0] = '.';
                     strcpy(ctx->RHS + 1, cp);
              }
       }

       /*
        * If there is no default hesiod realm set, we return an
        * error.
        */
       if (!ctx->RHS) {
              __set_errno(ENOEXEC);
              goto cleanup;
       }

#if 0
       if (res_ninit(ctx->res) < 0)
              goto cleanup;
#endif

       *context = ctx;
       return (0);

 cleanup:
       hesiod_end(ctx);
       return (-1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

char ** hesiod_resolve ( void *  context,
const char *  name,
const char *  type 
)

Definition at line 228 of file hesiod.c.

                                                                  {
       struct hesiod_p *ctx = (struct hesiod_p *) context;
       char *bindname = hesiod_to_bind(context, name, type);
       char **retvec;

       if (bindname == NULL)
              return (NULL);
       if (init(ctx) == -1) {
              free(bindname);
              return (NULL);
       }

       retvec = get_txt_records(ctx, ctx->classes[0], bindname);

       if (retvec == NULL && (errno == ENOENT || errno == ECONNREFUSED) && ctx->classes[1])
              retvec = get_txt_records(ctx, ctx->classes[1], bindname);


       free(bindname);
       return (retvec);
}

Here is the call graph for this function:

Here is the caller graph for this function:

char * hesiod_to_bind ( void *  context,
const char *  name,
const char *  type 
)

Definition at line 170 of file hesiod.c.

                                                                  {
       struct hesiod_p *ctx = (struct hesiod_p *) context;
       char *bindname;
       char **rhs_list = NULL;
       const char *RHS, *cp;
       char *endp;

       /* Decide what our RHS is, and set cp to the end of the actual name. */
       if ((cp = strchr(name, '@')) != NULL) {
              if (strchr(cp + 1, '.'))
                     RHS = cp + 1;
              else if ((rhs_list = hesiod_resolve(context, cp + 1,
                  "rhs-extension")) != NULL)
                     RHS = *rhs_list;
              else {
                     __set_errno(ENOENT);
                     return (NULL);
              }
       } else {
              RHS = ctx->RHS;
              cp = name + strlen(name);
       }

       /*
        * Allocate the space we need, including up to three periods and
        * the terminating NUL.
        */
       if ((bindname = malloc((cp - name) + strlen(type) + strlen(RHS) +
           (ctx->LHS ? strlen(ctx->LHS) : 0) + 4)) == NULL) {
              if (rhs_list)
                     hesiod_free_list(context, rhs_list);
              return NULL;
       }

       /* Now put together the DNS name. */
       endp = (char *) __mempcpy (bindname, name, cp - name);
       *endp++ = '.';
       endp = (char *) __stpcpy (endp, type);
       if (ctx->LHS) {
              if (ctx->LHS[0] != '.')
                     *endp++ = '.';
              endp = __stpcpy (endp, ctx->LHS);
       }
       if (RHS[0] != '.')
              *endp++ = '.';
       strcpy (endp, RHS);

       if (rhs_list)
              hesiod_free_list(context, rhs_list);

       return (bindname);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int init ( struct hesiod_p ctx) [static]

Definition at line 498 of file hesiod.c.

                           {

       if (!ctx->res && !__hesiod_res_get(ctx))
              return (-1);

       if (__res_maybe_init (ctx->res, 0) == -1)
              return (-1);

       return (0);
}

Here is the call graph for this function:

static int parse_config_file ( struct hesiod_p ctx,
const char *  filename 
) [static]

Definition at line 263 of file hesiod.c.

                                                              {
       char buf[MAXDNAME+7];
       FILE *fp;

       /*
        * Clear the existing configuration variable, just in case
        * they're set.
        */
       free(ctx->RHS);
       free(ctx->LHS);
       ctx->RHS = ctx->LHS = 0;
       /* Set default query classes. */
       ctx->classes[0] = C_IN;
       ctx->classes[1] = C_HS;

       /*
        * Now open and parse the file...
        */
       if (!(fp = fopen(filename, "r")))
              return (-1);

       while (fgets(buf, sizeof(buf), fp) != NULL) {
              char *key, *data, *cp, **cpp;

              cp = buf;
              if (*cp == '#' || *cp == '\n' || *cp == '\r')
                     continue;
              while(*cp == ' ' || *cp == '\t')
                     cp++;
              key = cp;
              while(*cp != ' ' && *cp != '\t' && *cp != '=')
                     cp++;
              *cp++ = '\0';

              while(*cp == ' ' || *cp == '\t' || *cp == '=')
                     cp++;
              data = cp;
              while(*cp != ' ' && *cp != '\n' && *cp != '\r')
                     cp++;
              *cp++ = '\0';

              cpp = NULL;
              if (strcasecmp(key, "lhs") == 0)
                     cpp = &ctx->LHS;
              else if (strcasecmp(key, "rhs") == 0)
                     cpp = &ctx->RHS;
              if (cpp) {
                     *cpp = strdup(data);
                     if (!*cpp)
                            goto cleanup;
              } else if (strcasecmp(key, "classes") == 0) {
                     int n = 0;
                     while (*data && n < 2) {
                            cp = strchrnul(data, ',');
                            if (*cp != '\0')
                                   *cp++ = '\0';
                            if (strcasecmp(data, "IN") == 0)
                                   ctx->classes[n++] = C_IN;
                            else if (strcasecmp(data, "HS") == 0)
                                   ctx->classes[n++] = C_HS;
                            data = cp;
                     }
                     if (n == 0) {
                            /* Restore the default.  Better than
                               nother at all.  */
                            ctx->classes[0] = C_IN;
                            ctx->classes[1] = C_HS;
                     } else if (n == 1
                               || ctx->classes[0] == ctx->classes[1])
                            ctx->classes[1] = 0;
              }
       }
       fclose(fp);
       return (0);

 cleanup:
       fclose(fp);
       free(ctx->RHS);
       free(ctx->LHS);
       ctx->RHS = ctx->LHS = 0;
       return (-1);
}

Here is the call graph for this function:

Here is the caller graph for this function: