X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=lib%2Fnss_wrapper%2Fnss_wrapper.c;h=4bde91ca3ac8926a80c8119422c4cd10112b1260;hb=736fa61a9546c48d03cbd75897f7e6956ed48c0e;hp=4b93f2d01fb22b54dab94228bd76b4d586ca0b1c;hpb=4ec47e739c024bbd2cb9ebcc310964011333eca4;p=obnox%2Fsamba%2Fsamba-obnox.git diff --git a/lib/nss_wrapper/nss_wrapper.c b/lib/nss_wrapper/nss_wrapper.c index 4b93f2d01fb..4bde91ca3ac 100644 --- a/lib/nss_wrapper/nss_wrapper.c +++ b/lib/nss_wrapper/nss_wrapper.c @@ -52,6 +52,8 @@ #include #include +#include + #include #include @@ -758,16 +760,17 @@ struct nwrap_entdata { struct nwrap_vector nwrap_addrdata; ssize_t aliases_count; +}; - struct nwrap_entdata *ed_next; - struct nwrap_entdata *ed_tail; +struct nwrap_entlist { + struct nwrap_entlist *next; + struct nwrap_entdata *ed; }; struct nwrap_he { struct nwrap_cache *cache; - struct nwrap_entdata *list; - struct nwrap_vector entdata; + struct nwrap_vector entries; int num; int idx; @@ -1562,14 +1565,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"); @@ -1759,7 +1763,7 @@ static void nwrap_files_cache_unload(struct nwrap_cache *nwrap) nwrap_lines_unload(nwrap); } -static void nwrap_files_cache_reload(struct nwrap_cache *nwrap) +static bool nwrap_files_cache_reload(struct nwrap_cache *nwrap) { struct stat st; int ret; @@ -1777,7 +1781,7 @@ reopen: "Unable to open '%s' readonly %d:%s", nwrap->path, nwrap->fd, strerror(errno)); - return; + return false; } nwrap->fd = fileno(nwrap->fp); @@ -1794,7 +1798,7 @@ reopen: fclose(nwrap->fp); nwrap->fp = NULL; nwrap->fd = -1; - return; + return false; } if (retried == false && st.st_nlink == 0) { @@ -1814,7 +1818,7 @@ reopen: NWRAP_LOG(NWRAP_LOG_TRACE, "st_mtime[%u] hasn't changed, skip reload", (unsigned)st.st_mtime); - return; + return true; } NWRAP_LOG(NWRAP_LOG_TRACE, @@ -1830,9 +1834,11 @@ reopen: if (!ok) { NWRAP_LOG(NWRAP_LOG_ERROR, "Failed to reload %s", nwrap->path); nwrap_files_cache_unload(nwrap); + return false; } NWRAP_LOG(NWRAP_LOG_TRACE, "Reloaded %s", nwrap->path); + return true; } /* @@ -2541,118 +2547,126 @@ static int nwrap_gr_copy_r(const struct group *src, struct group *dst, return 0; } -static bool nwrap_add_ai(char *const ip_addr, struct nwrap_entdata *const ed) +static struct nwrap_entlist *nwrap_entlist_init(struct nwrap_entdata *ed) { - ENTRY e = { - .key = ip_addr, - .data = (void *)ed, - }; - ENTRY *p; + struct nwrap_entlist *el; - p = hsearch(e, ENTER); - if (p == NULL) { - NWRAP_LOG(NWRAP_LOG_DEBUG, "Hash table is full"); - return false; + if (ed == NULL) { + NWRAP_LOG(NWRAP_LOG_ERROR, + "entry is NULL, can't create list item"); + return NULL; } - return true; -} + el = (struct nwrap_entlist *)malloc(sizeof(struct nwrap_entlist)); + if (el == NULL) { + NWRAP_LOG(NWRAP_LOG_ERROR, "malloc failed"); + return NULL; + } + + el->next = NULL; + el->ed = ed; + return el; +} -static bool nwrap_add_hname_add_new(char *const h_name, - struct nwrap_entdata *const ed) +static bool nwrap_ed_inventarize_add_new(char *const h_name, + struct nwrap_entdata *const ed) { ENTRY e; ENTRY *p; + struct nwrap_entlist *el; + + if (h_name == NULL) { + NWRAP_LOG(NWRAP_LOG_ERROR, "h_name NULL - can't add"); + return false; + } + + el = nwrap_entlist_init(ed); + if (el == NULL) { + return false; + } e.key = h_name; - e.data = (void *)ed; - ed->ed_tail = NULL; - ed->ed_next = NULL; + e.data = (void *)el; p = hsearch(e, ENTER); if (p == NULL) { - NWRAP_LOG(NWRAP_LOG_DEBUG, "Hash table is full!"); + NWRAP_LOG(NWRAP_LOG_ERROR, "Hash table is full!"); return false; } return true; } -static void nwrap_add_hname_add_to_existing(struct nwrap_entdata *const ed, - struct nwrap_entdata *const ed_dst) +static bool nwrap_ed_inventarize_add_to_existing(struct nwrap_entdata *const ed, + struct nwrap_entlist *const el) { - if (ed_dst->ed_tail != NULL) { - ed_dst->ed_tail->ed_next = ed; - if (ed_dst->ed_tail != ed) { - ed_dst->ed_tail = ed; - ed->ed_next = NULL; + struct nwrap_entlist *cursor; + struct nwrap_entlist *el_new; + + if (el == NULL) { + NWRAP_LOG(NWRAP_LOG_ERROR, "list is NULL, can not add"); + return false; + } + + + for (cursor = el; cursor->next != NULL; cursor = cursor->next) + { + if (cursor->ed == ed) { + return false; } - } else { - ed_dst->ed_tail = ed; } + + if (cursor->ed == ed) { + return false; + } + + el_new = nwrap_entlist_init(ed); + if (el_new == NULL) { + return false; + } + + cursor->next = el_new; + return true; } -static bool nwrap_add_hname_alias(char *const h_name_a, - struct nwrap_entdata *const ed) +static bool nwrap_ed_inventarize(char *const name, + struct nwrap_entdata *const ed) { ENTRY e; ENTRY *p; + bool ok; - assert(ed != NULL); - assert(h_name_a != NULL); - - e.key = h_name_a; + e.key = name; e.data = NULL; + NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key); + p = hsearch(e, FIND); if (p == NULL) { - NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", h_name_a); - nwrap_add_hname_add_new(h_name_a, ed); + NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", name); + ok = nwrap_ed_inventarize_add_new(name, ed); } else { - struct nwrap_entdata *ed_dst = (struct nwrap_entdata *)p->data; + struct nwrap_entlist *el = (struct nwrap_entlist *)p->data; - assert(p->data != NULL); - NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", h_name_a); - nwrap_add_hname_add_to_existing(ed, ed_dst); + NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", name); + ok = nwrap_ed_inventarize_add_to_existing(ed, el); } - return true; + return ok; } static bool nwrap_add_hname(struct nwrap_entdata *const ed) { char *const h_name = (char *const)(ed->ht.h_name); - ENTRY e; - ENTRY *p; unsigned i; + bool ok; - /* Maybe it's little bit late ... */ - assert(ed != NULL); - assert(h_name != NULL); - - e.key = h_name; - e.data = NULL; - NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching name: %s", e.key); - p = hsearch(e, FIND); - if (p == NULL) { - NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found. Adding...", h_name); - /* Just add alias and don't mess with metadata */ - nwrap_add_hname_add_new(h_name, ed); - - if (ed->ed_tail == NULL) { - ed->ed_tail = ed; - } - } else { - /* Element found. Add them to end of list */ - struct nwrap_entdata *ed_dst = (struct nwrap_entdata *)p->data; - - assert(p->data != NULL); - NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s found. Add record to list.", h_name); - nwrap_add_hname_add_to_existing(ed, ed_dst); + ok = nwrap_ed_inventarize(h_name, ed); + if (!ok) { + return false; } - /* Return true when list of aliases is empty */ if (ed->ht.h_aliases == NULL) { return true; } @@ -2662,13 +2676,13 @@ static bool nwrap_add_hname(struct nwrap_entdata *const ed) char *h_name_alias; h_name_alias = ed->ht.h_aliases[i]; - assert(h_name_alias != NULL); NWRAP_LOG(NWRAP_LOG_DEBUG, "Add alias: %s", h_name_alias); - if (!nwrap_add_hname_alias(h_name_alias, ed)) { - NWRAP_LOG(NWRAP_LOG_DEBUG, + if (!nwrap_ed_inventarize(h_name_alias, ed)) { + NWRAP_LOG(NWRAP_LOG_ERROR, "Unable to add alias: %s", h_name_alias); + return false; } } @@ -2685,6 +2699,7 @@ static bool nwrap_he_parse_line(struct nwrap_cache *nwrap, char *line) char *n; char *ip; + bool ok; struct nwrap_entdata *ed = (struct nwrap_entdata *) malloc(sizeof(struct nwrap_entdata)); @@ -2829,12 +2844,19 @@ 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); + nwrap_vector_add_item(&(nwrap_he->entries), (void *const)ed); ed->aliases_count = aliases_count; /* Inventarize item */ - nwrap_add_hname(ed); - nwrap_add_ai(ip, ed); + ok = nwrap_add_hname(ed); + if (!ok) { + return false; + } + + ok = nwrap_ed_inventarize(ip, ed); + if (!ok) { + return false; + } nwrap_he->num++; return true; @@ -2847,14 +2869,14 @@ static void nwrap_he_unload(struct nwrap_cache *nwrap) struct nwrap_entdata *ed; 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_he->num = 0; nwrap_he->idx = 0; @@ -2866,12 +2888,17 @@ static struct passwd *nwrap_files_getpwnam(struct nwrap_backend *b, const char *name) { int i; + bool ok; (void) b; /* unused */ NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name); - nwrap_files_cache_reload(nwrap_pw_global.cache); + ok = nwrap_files_cache_reload(nwrap_pw_global.cache); + if (!ok) { + NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading passwd file"); + return NULL; + } for (i=0; i= nwrap_pw_global.num) { @@ -3021,7 +3058,13 @@ static struct spwd *nwrap_files_getspent(void) struct spwd *sp; if (nwrap_sp_global.idx == 0) { - nwrap_files_cache_reload(nwrap_sp_global.cache); + bool ok; + + ok = nwrap_files_cache_reload(nwrap_sp_global.cache); + if (!ok) { + NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file"); + return NULL; + } } if (nwrap_sp_global.idx >= nwrap_sp_global.num) { @@ -3047,10 +3090,15 @@ static void nwrap_files_endspent(void) static struct spwd *nwrap_files_getspnam(const char *name) { int i; + bool ok; NWRAP_LOG(NWRAP_LOG_DEBUG, "Lookup user %s in files", name); - nwrap_files_cache_reload(nwrap_sp_global.cache); + ok = nwrap_files_cache_reload(nwrap_sp_global.cache); + if (!ok) { + NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading shadow file"); + return NULL; + } for (i=0; i= nwrap_gr_global.num) { @@ -3281,8 +3345,7 @@ static int nwrap_files_gethostbyname(const char *name, int af, struct hostent *result, struct nwrap_vector *addr_list) { - struct nwrap_entdata *ed_head; - struct nwrap_entdata *ed_cur; + struct nwrap_entlist *el; struct hostent *he; char *h_name_lower; ENTRY e; @@ -3290,8 +3353,13 @@ static int nwrap_files_gethostbyname(const char *name, int af, char canon_name[DNS_NAME_MAX] = { 0 }; size_t name_len; bool he_found = false; + bool ok; - nwrap_files_cache_reload(nwrap_he_global.cache); + ok = nwrap_files_cache_reload(nwrap_he_global.cache); + if (!ok) { + NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file"); + goto no_ent; + } name_len = strlen(name); if (name_len < sizeof(canon_name) && name[name_len - 1] == '.') { @@ -3331,9 +3399,9 @@ static int nwrap_files_gethostbyname(const char *name, int af, } /* Iterate through results */ - ed_head = (struct nwrap_entdata *)e_p->data; - for (ed_cur = ed_head; ed_cur != NULL; ed_cur = ed_cur->ed_next) { - he = &(ed_cur->ht); + for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next) + { + he = &(el->ed->ht); /* Filter by address familiy if provided */ if (af != AF_UNSPEC && he->h_addrtype != af) { @@ -3355,7 +3423,7 @@ static int nwrap_files_gethostbyname(const char *name, int af, he->h_name); he_found = true; } - nwrap_vector_merge(addr_list, &ed_cur->nwrap_addrdata); + nwrap_vector_merge(addr_list, &el->ed->nwrap_addrdata); result->h_addr_list = nwrap_vector_head(addr_list); } @@ -3436,25 +3504,31 @@ int gethostbyname_r(const char *name, } #endif -static struct addrinfo *nwrap_files_getaddrinfo(const char *name, - unsigned short port, - const struct addrinfo *hints, - struct addrinfo **ai_tail) +static int nwrap_files_getaddrinfo(const char *name, + unsigned short port, + const struct addrinfo *hints, + struct addrinfo **ai) { - struct nwrap_entdata *ed_head; - struct nwrap_entdata *ed_cur; + 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; - nwrap_files_cache_reload(nwrap_he_global.cache); + ok = nwrap_files_cache_reload(nwrap_he_global.cache); + if (!ok) { + NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file"); + return EAI_SYSTEM; + } name_len = strlen(name); if (name_len < DNS_NAME_MAX && name[name_len - 1] == '.') { @@ -3465,7 +3539,7 @@ static struct addrinfo *nwrap_files_getaddrinfo(const char *name, if (!str_tolower_copy(&h_name_lower, name)) { NWRAP_LOG(NWRAP_LOG_DEBUG, "Out of memory while converting to lower case"); - return NULL; + return EAI_MEMORY; } NWRAP_LOG(NWRAP_LOG_DEBUG, "Searching for name: %s", h_name_lower); @@ -3476,48 +3550,60 @@ static struct addrinfo *nwrap_files_getaddrinfo(const char *name, NWRAP_LOG(NWRAP_LOG_DEBUG, "Name %s not found.", h_name_lower); SAFE_FREE(h_name_lower); errno = ENOENT; - return NULL; + return EAI_NONAME; } NWRAP_LOG(NWRAP_LOG_DEBUG, "Name: %s found.", h_name_lower); SAFE_FREE(h_name_lower); - ed_head = (struct nwrap_entdata *)e_p->data; - - for (ed_cur = ed_head; ed_cur != NULL; ed_cur = ed_cur->ed_next) { - int rc; + rc = EAI_NONAME; + for (el = (struct nwrap_entlist *)e_p->data; el != NULL; el = el->next) + { + int rc2; + struct addrinfo *ai_new = NULL; - he = &(ed_cur->ht); + he = &(el->ed->ht); if (hints->ai_family != AF_UNSPEC && - he->h_addrtype != hints->ai_family) { + he->h_addrtype != hints->ai_family) + { + NWRAP_LOG(NWRAP_LOG_DEBUG, + "Entry found but with wrong AF - " + "remembering EAI_ADDRINFO."); + rc = EAI_ADDRFAMILY; continue; } /* Function allocates memory and returns it in ai. */ - rc = nwrap_convert_he_ai(he, + rc2 = nwrap_convert_he_ai(he, port, hints, - &ai, + &ai_new, skip_canonname); - if (rc != 0) { - /* FIXME: Investigate if this is nice to do... */ - NWRAP_LOG(NWRAP_LOG_ERROR, - "Error in converting he to ai! Skipping."); - continue; + 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) { + rc = 0; } - *ai_tail = ai; - return ai_head; + *ai = ai_head; + + return rc; } static struct hostent *nwrap_files_gethostbyaddr(const void *addr, @@ -3528,10 +3614,15 @@ static struct hostent *nwrap_files_gethostbyaddr(const void *addr, struct nwrap_entdata *ed; const char *a; size_t i; + bool ok; (void) len; /* unused */ - nwrap_files_cache_reload(nwrap_he_global.cache); + ok = nwrap_files_cache_reload(nwrap_he_global.cache); + if (!ok) { + NWRAP_LOG(NWRAP_LOG_ERROR, "error loading hosts file"); + return NULL; + } a = inet_ntop(type, addr, ip, sizeof(ip)); if (a == NULL) { @@ -3539,7 +3630,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) { @@ -3603,7 +3694,13 @@ static struct hostent *nwrap_files_gethostent(void) struct hostent *he; if (nwrap_he_global.idx == 0) { - nwrap_files_cache_reload(nwrap_he_global.cache); + bool ok; + + ok = nwrap_files_cache_reload(nwrap_he_global.cache); + if (!ok) { + NWRAP_LOG(NWRAP_LOG_ERROR, "Error loading hosts file"); + return NULL; + } } if (nwrap_he_global.idx >= nwrap_he_global.num) { @@ -3611,7 +3708,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); @@ -4957,12 +5054,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); @@ -5026,7 +5134,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; @@ -5039,6 +5146,7 @@ static int nwrap_getaddrinfo(const char *node, } addr = { .family = AF_UNSPEC, }; + int rc; if (node == NULL && service == NULL) { return EAI_NONAME; @@ -5102,23 +5210,32 @@ static int nwrap_getaddrinfo(const char *node, } valid_port: - if (hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET) { - int rc = inet_pton(AF_INET, node, &addr.in.v4); - if (rc == 1) { - addr.family = AF_INET; - } + + rc = inet_pton(AF_INET, node, &addr.in.v4); + if (rc == 1) { + addr.family = AF_INET; } #ifdef HAVE_IPV6 if (addr.family == AF_UNSPEC) { - int rc = inet_pton(AF_INET6, node, &addr.in.v6); + rc = inet_pton(AF_INET6, node, &addr.in.v6); if (rc == 1) { addr.family = AF_INET6; } } #endif - ai = nwrap_files_getaddrinfo(node, port, hints, &ai_tail); - if (ai == NULL) { + if (addr.family == AF_UNSPEC) { + if (hints->ai_flags & AI_NUMERICHOST) { + return EAI_NONAME; + } + } else if ((hints->ai_family != AF_UNSPEC) && + (hints->ai_family != addr.family)) + { + return EAI_ADDRFAMILY; + } + + rc = nwrap_files_getaddrinfo(node, port, hints, &ai); + if (rc != 0) { int ret; struct addrinfo *p = NULL; @@ -5133,63 +5250,58 @@ valid_port: return 0; } - return EAI_SYSTEM; - } - - 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 */ + return rc; } + /* + * 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;