nwrap: Don't fail if we want to add an existing entry
[samba.git] / lib / nss_wrapper / nss_wrapper.c
index 0b57cbc62427ab3413ef115e1a75b4c8258747cf..f48b9cc7e8d65d1f992a014d8dad80fc2ed833a8 100644 (file)
@@ -52,6 +52,8 @@
 #include <unistd.h>
 #include <ctype.h>
 
+#include <netinet/in.h>
+
 #include <search.h>
 #include <assert.h>
 
@@ -768,8 +770,8 @@ struct nwrap_entlist {
 struct nwrap_he {
        struct nwrap_cache *cache;
 
-       struct nwrap_entdata *list;
-       struct nwrap_vector entdata;
+       struct nwrap_vector entries;
+       struct nwrap_vector lists;
 
        int num;
        int idx;
@@ -1564,14 +1566,15 @@ static void nwrap_init(void)
                                  "Error parsing NSS_WRAPPER_MAX_HOSTENTS "
                                  "value or value is too small. "
                                  "Using default value: %lu.",
-                                 max_hostents);
+                                 (unsigned long)max_hostents);
                } else {
                        max_hostents = max_hostents_tmp;
                }
        }
        /* Initialize hash table */
        NWRAP_LOG(NWRAP_LOG_DEBUG,
-                 "Initializing hash table of size %lu items.", max_hostents);
+                 "Initializing hash table of size %lu items.",
+                 (unsigned long)max_hostents);
        if (hcreate(max_hostents) == 0) {
                NWRAP_LOG(NWRAP_LOG_ERROR,
                          "Failed to initialize hash table");
@@ -2573,6 +2576,7 @@ static bool nwrap_ed_inventarize_add_new(char *const h_name,
        ENTRY e;
        ENTRY *p;
        struct nwrap_entlist *el;
+       bool ok;
 
        if (h_name == NULL) {
                NWRAP_LOG(NWRAP_LOG_ERROR, "h_name NULL - can't add");
@@ -2593,6 +2597,13 @@ static bool nwrap_ed_inventarize_add_new(char *const h_name,
                return false;
        }
 
+       ok = nwrap_vector_add_item(&(nwrap_he_global.lists), (void *)el);
+       if (!ok) {
+               NWRAP_LOG(NWRAP_LOG_ERROR,
+                         "Failed to add list entry to vector.");
+               return false;
+       }
+
        return true;
 }
 
@@ -2607,21 +2618,22 @@ static bool nwrap_ed_inventarize_add_to_existing(struct nwrap_entdata *const ed,
                return false;
        }
 
-       el_new = nwrap_entlist_init(ed);
-       if (el_new == NULL) {
-               return false;
-       }
 
        for (cursor = el; cursor->next != NULL; cursor = cursor->next)
        {
                if (cursor->ed == ed) {
-                       free(el_new);
-                       return false;
+                       /* The entry already exists in this list. */
+                       return true;
                }
        }
 
        if (cursor->ed == ed) {
-               free(el_new);
+               /* The entry already exists in this list. */
+               return true;
+       }
+
+       el_new = nwrap_entlist_init(ed);
+       if (el_new == NULL) {
                return false;
        }
 
@@ -2756,8 +2768,13 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
        }
        ip = i;
 
-       nwrap_vector_add_item(&(ed->nwrap_addrdata),
-                             (void *const)ed->addr.host_addr);
+       ok = nwrap_vector_add_item(&(ed->nwrap_addrdata),
+                                  (void *const)ed->addr.host_addr);
+       if (!ok) {
+               NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add addrdata to vector");
+               free(ed);
+               return false;
+       }
        ed->ht.h_addr_list = nwrap_vector_head(&ed->nwrap_addrdata);
 
        p++;
@@ -2843,7 +2860,12 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line)
                aliases_count += 1;
        }
 
-       nwrap_vector_add_item(&(nwrap_he->entdata), (void *const)ed);
+       ok = nwrap_vector_add_item(&(nwrap_he->entries), (void *const)ed);
+       if (!ok) {
+               NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add entry to vector");
+               free(ed);
+               return false;
+       }
 
        ed->aliases_count = aliases_count;
        /* Inventarize item */
@@ -2866,16 +2888,30 @@ static void nwrap_he_unload(struct nwrap_cache *nwrap)
        struct nwrap_he *nwrap_he =
                (struct nwrap_he *)nwrap->private_data;
        struct nwrap_entdata *ed;
+       struct nwrap_entlist *el;
        size_t i;
 
-       nwrap_vector_foreach (ed, nwrap_he->entdata, i)
+       nwrap_vector_foreach (ed, nwrap_he->entries, i)
        {
                SAFE_FREE(ed->nwrap_addrdata.items);
                SAFE_FREE(ed->ht.h_aliases);
                SAFE_FREE(ed);
        }
-       SAFE_FREE(nwrap_he->entdata.items);
-       nwrap_he->entdata.count = nwrap_he->entdata.capacity = 0;
+       SAFE_FREE(nwrap_he->entries.items);
+       nwrap_he->entries.count = nwrap_he->entries.capacity = 0;
+
+       nwrap_vector_foreach(el, nwrap_he->lists, i)
+       {
+               while (el != NULL) {
+                       struct nwrap_entlist *el_next;
+
+                       el_next = el->next;
+                       SAFE_FREE(el);
+                       el = el_next;
+               }
+       }
+       SAFE_FREE(nwrap_he->lists.items);
+       nwrap_he->lists.count = nwrap_he->lists.capacity = 0;
 
        nwrap_he->num = 0;
        nwrap_he->idx = 0;
@@ -3506,19 +3542,19 @@ int gethostbyname_r(const char *name,
 static int nwrap_files_getaddrinfo(const char *name,
                                   unsigned short port,
                                   const struct addrinfo *hints,
-                                  struct addrinfo **ai,
-                                  struct addrinfo **ai_tail)
+                                  struct addrinfo **ai)
 {
        struct nwrap_entlist *el;
        struct hostent *he;
-       struct addrinfo *_ai = NULL;
        struct addrinfo *ai_head = NULL;
-       struct addrinfo *ai_prev = NULL;
+       struct addrinfo *ai_cur = NULL;
        char *h_name_lower;
        size_t name_len;
        char canon_name[DNS_NAME_MAX] = { 0 };
        bool skip_canonname = false;
-       ENTRY e = { 0 };
+       ENTRY e = {
+               .key = NULL,
+       };
        ENTRY *e_p = NULL;
        int rc;
        bool ok;
@@ -3558,6 +3594,7 @@ static int nwrap_files_getaddrinfo(const char *name,
        for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next)
        {
                int rc2;
+               struct addrinfo *ai_new = NULL;
 
                he = &(el->ed->ht);
 
@@ -3575,21 +3612,24 @@ static int nwrap_files_getaddrinfo(const char *name,
                rc2 = nwrap_convert_he_ai(he,
                                         port,
                                         hints,
-                                        &_ai,
+                                        &ai_new,
                                         skip_canonname);
                if (rc2 != 0) {
                        NWRAP_LOG(NWRAP_LOG_ERROR, "Error converting he to ai");
+                       if (ai_head != NULL) {
+                               freeaddrinfo(ai_head);
+                       }
                        return rc2;
                }
                skip_canonname = true;
 
                if (ai_head == NULL) {
-                       ai_head = _ai;
+                       ai_head = ai_new;
                }
-               if (ai_prev != NULL) {
-                       ai_prev->ai_next = _ai;
+               if (ai_cur != NULL) {
+                       ai_cur->ai_next = ai_new;
                }
-               ai_prev = _ai;
+               ai_cur = ai_new;
        }
 
        if (ai_head != NULL) {
@@ -3597,7 +3637,6 @@ static int nwrap_files_getaddrinfo(const char *name,
        }
 
        *ai = ai_head;
-       *ai_tail = _ai;
 
        return rc;
 }
@@ -3626,7 +3665,7 @@ static struct hostent *nwrap_files_gethostbyaddr(const void *addr,
                return NULL;
        }
 
-       nwrap_vector_foreach(ed, nwrap_he_global.entdata, i)
+       nwrap_vector_foreach(ed, nwrap_he_global.entries, i)
        {
                he = &(ed->ht);
                if (he->h_addrtype != type) {
@@ -3704,7 +3743,7 @@ static struct hostent *nwrap_files_gethostent(void)
                return NULL;
        }
 
-       he = &((struct nwrap_entdata *)nwrap_he_global.entdata.items[nwrap_he_global.idx++])->ht;
+       he = &((struct nwrap_entdata *)nwrap_he_global.entries.items[nwrap_he_global.idx++])->ht;
 
        NWRAP_LOG(NWRAP_LOG_DEBUG, "return hosts[%s]", he->h_name);
 
@@ -5050,12 +5089,23 @@ static int nwrap_convert_he_ai(const struct hostent *he,
                return EAI_MEMORY;
        }
 
-       ai->ai_flags = 0;
+       ai->ai_flags = hints->ai_flags;
        ai->ai_family = he->h_addrtype;
        ai->ai_socktype = hints->ai_socktype;
        ai->ai_protocol = hints->ai_protocol;
        ai->ai_canonname = NULL;
 
+       if (ai->ai_socktype == 0) {
+               ai->ai_socktype = SOCK_DGRAM;
+       }
+       if (ai->ai_protocol == 0) {
+               if (ai->ai_socktype == SOCK_DGRAM) {
+                       ai->ai_protocol = IPPROTO_UDP;
+               } else if (ai->ai_socktype == SOCK_STREAM) {
+                       ai->ai_protocol = IPPROTO_TCP;
+               }
+       }
+
        ai->ai_addrlen = socklen;
        ai->ai_addr = (void *)(ai + 1);
 
@@ -5119,7 +5169,6 @@ static int nwrap_getaddrinfo(const char *node,
                             struct addrinfo **res)
 {
        struct addrinfo *ai = NULL;
-       struct addrinfo *ai_tail;
        unsigned short port = 0;
        struct {
                int family;
@@ -5220,7 +5269,7 @@ valid_port:
                return EAI_ADDRFAMILY;
        }
 
-       rc = nwrap_files_getaddrinfo(node, port, hints, &ai, &ai_tail);
+       rc = nwrap_files_getaddrinfo(node, port, hints, &ai);
        if (rc != 0) {
                int ret;
                struct addrinfo *p = NULL;
@@ -5239,60 +5288,55 @@ valid_port:
                return rc;
        }
 
-       if (ai->ai_flags == 0) {
-               ai->ai_flags = hints->ai_flags;
-       }
-       if (ai->ai_socktype == 0) {
-               ai->ai_socktype = SOCK_DGRAM;
-       }
-       if (ai->ai_protocol == 0 && ai->ai_socktype == SOCK_DGRAM) {
-               ai->ai_protocol = 17; /* UDP */
-       } else if (ai->ai_protocol == 0 && ai->ai_socktype == SOCK_STREAM) {
-               ai->ai_protocol = 6; /* TCP */
-       }
-
+       /*
+        * If the socktype was not specified, duplicate
+        * each ai returned, so that we have variants for
+        * both UDP and TCP.
+        */
        if (hints->ai_socktype == 0) {
-               /* Add second ai */
-               struct addrinfo *ai_head = ai;
-               struct addrinfo *ai_tmp;
-               struct addrinfo *ai_new_tail = ai_tail;
-
-               /* Add at least one more struct */
-               do {
-                       /* CHECKS! */
-                       ai_tmp = malloc(sizeof(struct addrinfo));
-                       memcpy(ai_tmp, ai_head, sizeof(struct addrinfo));
-                       ai_tmp->ai_next = NULL;
+               struct addrinfo *ai_cur;
 
-                       /* We need a deep copy or freeaddrinfo() will blow up */
-                       if (ai_head->ai_canonname != NULL) {
-                               ai_tmp->ai_canonname =
-                                       strdup(ai_head->ai_canonname);
+               /* freeaddrinfo() frees ai_canonname and ai so allocate them */
+               for (ai_cur = ai; ai_cur != NULL; ai_cur = ai_cur->ai_next) {
+                       struct addrinfo *ai_new;
+
+                       /* duplicate the current entry */
+
+                       ai_new = malloc(sizeof(struct addrinfo));
+                       if (ai_new == NULL) {
+                               freeaddrinfo(ai);
+                               return EAI_MEMORY;
                        }
-                       /* ai_head should point inside hints. */
-                       ai_tmp->ai_addr = ai_head->ai_addr;
 
-                       if (ai_head->ai_flags == 0) {
-                               ai_tmp->ai_flags = hints->ai_flags;
+                       memcpy(ai_new, ai_cur, sizeof(struct addrinfo));
+                       ai_new->ai_next = NULL;
+
+                       /* We need a deep copy or freeaddrinfo() will blow up */
+                       if (ai_cur->ai_canonname != NULL) {
+                               ai_new->ai_canonname =
+                                       strdup(ai_cur->ai_canonname);
                        }
-                       if (ai_head->ai_socktype == SOCK_DGRAM) {
-                               ai_tmp->ai_socktype = SOCK_STREAM;
-                       } else if (ai_head->ai_socktype == SOCK_STREAM) {
-                               ai_tmp->ai_socktype = SOCK_DGRAM;
+
+                       if (ai_cur->ai_socktype == SOCK_DGRAM) {
+                               ai_new->ai_socktype = SOCK_STREAM;
+                       } else if (ai_cur->ai_socktype == SOCK_STREAM) {
+                               ai_new->ai_socktype = SOCK_DGRAM;
                        }
-                       if (ai_head->ai_socktype == SOCK_DGRAM) {
-                               ai_tmp->ai_protocol = 17; /* UDP */
-                       } else if (ai_head->ai_socktype == SOCK_STREAM) {
-                               ai_tmp->ai_protocol = 6; /* TCP */
+                       if (ai_cur->ai_protocol == IPPROTO_TCP) {
+                               ai_new->ai_protocol = IPPROTO_UDP;
+                       } else if (ai_cur->ai_protocol == IPPROTO_UDP) {
+                               ai_new->ai_protocol = IPPROTO_TCP;
                        }
-                       ai_new_tail->ai_next = ai_tmp;
-                       ai_new_tail = ai_tmp;
 
-                       if (ai_head == ai_tail) {
-                               break;
-                       }
-                       ai_head = ai_head->ai_next;
-               } while (1);
+                       /* now insert the new entry */
+
+                       ai_new->ai_next = ai_cur->ai_next;
+                       ai_cur->ai_next = ai_new;
+
+                       /* and move on (don't duplicate the new entry) */
+
+                       ai_cur = ai_new;
+               }
        }
 
        *res = ai;
@@ -5509,6 +5553,20 @@ void nwrap_destructor(void)
                nwrap_pw_global.num = 0;
        }
 
+#if defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM)
+       if (nwrap_sp_global.cache != NULL) {
+               struct nwrap_cache *c = nwrap_sp_global.cache;
+
+               nwrap_files_cache_unload(c);
+               if (c->fd >= 0) {
+                       fclose(c->fp);
+                       c->fd = -1;
+               }
+
+               nwrap_sp_global.num = 0;
+       }
+#endif /* defined(HAVE_SHADOW_H) && defined(HAVE_GETSPNAM) */
+
        if (nwrap_he_global.cache != NULL) {
                struct nwrap_cache *c = nwrap_he_global.cache;
 
@@ -5521,6 +5579,11 @@ void nwrap_destructor(void)
                nwrap_he_global.num = 0;
        }
 
+       free(user_addrlist.items);
+#ifdef HAVE_GETHOSTBYNAME2
+       free(user_addrlist2.items);
+#endif
+
        hdestroy();
        NWRAP_UNLOCK_ALL;
 }