-rename fest for symbols moved from GNUNET_NAMESTORE_ to new GNUNET_GNSRECORD_ library
[oweals/gnunet.git] / src / gnsrecord / gnsrecord.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009-2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file gnsrecord/gnsrecord.c
23  * @brief API to access GNS record data
24  * @author Martin Schanzenbach
25  * @author Matthias Wachs
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_conversation_service.h"
33 #include "gnunet_dnsparser_lib.h"
34 #include "gnunet_gnsrecord_lib.h"
35 #include "gnunet_tun_lib.h"
36
37
38 #define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
39
40
41 /**
42  * Convert the 'value' of a record to a string.
43  *
44  * @param type type of the record
45  * @param data value in binary encoding
46  * @param data_size number of bytes in @a data
47  * @return NULL on error, otherwise human-readable representation of the value
48  */
49 char *
50 GNUNET_GNSRECORD_value_to_string (uint32_t type,
51                                   const void *data,
52                                   size_t data_size)
53 {
54   const char *cdata;
55   char* result;
56   char tmp[INET6_ADDRSTRLEN];
57
58   switch (type)
59   {
60   case 0:
61     return NULL;
62   case GNUNET_DNSPARSER_TYPE_A:
63     if (data_size != sizeof (struct in_addr))
64       return NULL;
65     if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp)))
66       return NULL;
67     return GNUNET_strdup (tmp);
68   case GNUNET_DNSPARSER_TYPE_NS:
69     {
70       char *ns;
71       size_t off;
72
73       off = 0;
74       ns = GNUNET_DNSPARSER_parse_name (data,
75                                         data_size,
76                                         &off);
77       if ( (NULL == ns) ||
78            (off != data_size) )
79       {
80         GNUNET_break_op (0);
81         return NULL;
82       }
83       return ns;
84     }
85   case GNUNET_DNSPARSER_TYPE_CNAME:
86     {
87       char *cname;
88       size_t off;
89
90       off = 0;
91       cname = GNUNET_DNSPARSER_parse_name (data,
92                                            data_size,
93                                            &off);
94       if ( (NULL == cname) ||
95            (off != data_size) )
96       {
97         GNUNET_break_op (0);
98         GNUNET_free_non_null (cname);
99         return NULL;
100       }
101       return cname;
102     }
103   case GNUNET_DNSPARSER_TYPE_SOA:
104     {
105       struct GNUNET_DNSPARSER_SoaRecord *soa;
106       size_t off;
107
108       off = 0;
109       soa = GNUNET_DNSPARSER_parse_soa (data,
110                                         data_size,
111                                         &off);
112       if ( (NULL == soa) ||
113            (off != data_size) )
114       {
115         GNUNET_break_op (0);
116         return NULL;
117       }
118       GNUNET_asprintf (&result,
119                        "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
120                        soa->rname,
121                        soa->mname,
122                        soa->serial,
123                        soa->refresh,
124                        soa->retry,
125                        soa->expire,
126                        soa->minimum_ttl);
127       GNUNET_DNSPARSER_free_soa (soa);
128       return result;
129     }
130   case GNUNET_DNSPARSER_TYPE_PTR:
131     {
132       char *ptr;
133       size_t off;
134
135       off = 0;
136       ptr = GNUNET_DNSPARSER_parse_name (data,
137                                            data_size,
138                                            &off);
139       if ( (NULL == ptr) ||
140            (off != data_size) )
141       {
142         GNUNET_break_op (0);
143         GNUNET_free_non_null (ptr);
144         return NULL;
145       }
146       return ptr;
147     }
148   case GNUNET_DNSPARSER_TYPE_MX:
149     {
150       struct GNUNET_DNSPARSER_MxRecord *mx;
151       size_t off;
152
153       off = 0;
154       mx = GNUNET_DNSPARSER_parse_mx (data,
155                                       data_size,
156                                       &off);
157       if ( (NULL == mx) ||
158            (off != data_size) )
159       {
160         GNUNET_break_op (0);
161         GNUNET_free_non_null (mx);
162         return NULL;
163       }
164       GNUNET_asprintf (&result,
165                        "%hu,%s",
166                        mx->preference,
167                        mx->mxhost);
168       GNUNET_DNSPARSER_free_mx (mx);
169       return result;
170     }
171   case GNUNET_DNSPARSER_TYPE_TXT:
172     return GNUNET_strndup (data, data_size);
173   case GNUNET_DNSPARSER_TYPE_AAAA:
174     if (data_size != sizeof (struct in6_addr))
175       return NULL;
176     if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp)))
177       return NULL;
178     return GNUNET_strdup (tmp);
179   case GNUNET_GNSRECORD_TYPE_PKEY:
180     if (data_size != sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))
181       return NULL;
182     return GNUNET_CRYPTO_ecdsa_public_key_to_string (data);
183   case GNUNET_GNSRECORD_TYPE_PHONE:
184     {
185       const struct GNUNET_CONVERSATION_PhoneRecord *pr;
186       char *ret;
187       char *pkey;
188
189       if (data_size != sizeof (struct GNUNET_CONVERSATION_PhoneRecord))
190         return NULL;
191       pr = data;
192       if (0 != ntohl (pr->version))
193         return NULL;
194       pkey = GNUNET_CRYPTO_eddsa_public_key_to_string (&pr->peer.public_key);
195       GNUNET_asprintf (&ret,
196                        "%u-%s",
197                        ntohl (pr->line),
198                        pkey);
199       GNUNET_free (pkey);
200       return ret;
201     }
202   case GNUNET_GNSRECORD_TYPE_PSEU:
203     return GNUNET_strndup (data, data_size);
204   case GNUNET_GNSRECORD_TYPE_LEHO:
205     return GNUNET_strndup (data, data_size);
206   case GNUNET_GNSRECORD_TYPE_VPN:
207     {
208       const struct GNUNET_TUN_GnsVpnRecord *vpn;
209       char* vpn_str;
210
211       cdata = data;
212       if ( (data_size <= sizeof (struct GNUNET_TUN_GnsVpnRecord)) ||
213            ('\0' != cdata[data_size - 1]) )
214         return NULL; /* malformed */
215       vpn = data;
216       if (0 == GNUNET_asprintf (&vpn_str, "%u %s %s",
217                                 (unsigned int) ntohs (vpn->proto),
218                                 (const char*) GNUNET_i2s_full (&vpn->peer),
219                                 (const char*) &vpn[1]))
220       {
221         GNUNET_free (vpn_str);
222         return NULL;
223       }
224       return vpn_str;
225     }
226   case GNUNET_GNSRECORD_TYPE_GNS2DNS:
227     {
228       char *ns;
229       size_t off;
230
231       off = 0;
232       ns = GNUNET_DNSPARSER_parse_name (data,
233                                         data_size,
234                                         &off);
235       if ( (NULL == ns) ||
236            (off != data_size) )
237       {
238         GNUNET_break_op (0);
239         GNUNET_free_non_null (ns);
240         return NULL;
241       }
242       return ns;
243     }
244   case GNUNET_DNSPARSER_TYPE_SRV:
245     {
246       struct GNUNET_DNSPARSER_SrvRecord *srv;
247       size_t off;
248
249       off = 0;
250       srv = GNUNET_DNSPARSER_parse_srv ("+", /* FIXME: is this OK? */
251                                         data,
252                                         data_size,
253                                         &off);
254       if ( (NULL == srv) ||
255            (off != data_size) )
256       {
257         GNUNET_break_op (0);
258         return NULL;
259       }
260       GNUNET_asprintf (&result,
261                        "%d %d %d _%s._%s.%s",
262                        srv->priority,
263                        srv->weight,
264                        srv->port,
265                        srv->service,
266                        srv->proto,
267                        srv->domain_name);
268       GNUNET_DNSPARSER_free_srv (srv);
269       return result;
270     }
271   case GNUNET_DNSPARSER_TYPE_TLSA:
272     {
273       const struct GNUNET_TUN_DnsTlsaRecord *tlsa;
274       char* tlsa_str;
275
276       cdata = data;
277       if ( (data_size <= sizeof (struct GNUNET_TUN_DnsTlsaRecord)) ||
278            ('\0' != cdata[data_size - 1]) )
279         return NULL; /* malformed */
280       tlsa = data;
281       if (0 == GNUNET_asprintf (&tlsa_str,
282                                 "%c %c %c %s",
283                                 tlsa->usage,
284                                 tlsa->selector,
285                                 tlsa->matching_type,
286                                 (const char *) &tlsa[1]))
287       {
288         GNUNET_free (tlsa_str);
289         return NULL;
290       }
291       return tlsa_str;
292     }
293   default:
294     GNUNET_break (0);
295   }
296   GNUNET_break (0); // not implemented
297   return NULL;
298 }
299
300
301 /**
302  * Convert human-readable version of a 'value' of a record to the binary
303  * representation.
304  *
305  * @param type type of the record
306  * @param s human-readable string
307  * @param data set to value in binary encoding (will be allocated)
308  * @param data_size set to number of bytes in @a data
309  * @return #GNUNET_OK on success
310  */
311 int
312 GNUNET_GNSRECORD_string_to_value (uint32_t type,
313                                   const char *s,
314                                   void **data,
315                                   size_t *data_size)
316 {
317   struct in_addr value_a;
318   struct in6_addr value_aaaa;
319   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
320   struct GNUNET_TUN_GnsVpnRecord *vpn;
321   struct GNUNET_TUN_DnsTlsaRecord *tlsa;
322   char s_peer[103 + 1];
323   char s_serv[253 + 1];
324   unsigned int proto;
325
326   if (NULL == s)
327     return GNUNET_SYSERR;
328   switch (type)
329   {
330   case 0:
331     LOG (GNUNET_ERROR_TYPE_ERROR,
332          _("Unsupported record type %d\n"),
333          (int) type);
334     return GNUNET_SYSERR;
335   case GNUNET_DNSPARSER_TYPE_A:
336     if (1 != inet_pton (AF_INET, s, &value_a))
337     {
338       LOG (GNUNET_ERROR_TYPE_ERROR,
339            _("Unable to parse IPv4 address `%s'\n"),
340            s);
341       return GNUNET_SYSERR;
342     }
343     *data = GNUNET_malloc (sizeof (struct in_addr));
344     memcpy (*data, &value_a, sizeof (value_a));
345     *data_size = sizeof (value_a);
346     return GNUNET_OK;
347   case GNUNET_DNSPARSER_TYPE_NS:
348     {
349       char nsbuf[256];
350       size_t off;
351
352       off = 0;
353       if (GNUNET_OK !=
354           GNUNET_DNSPARSER_builder_add_name (nsbuf,
355                                              sizeof (nsbuf),
356                                              &off,
357                                              s))
358       {
359         LOG (GNUNET_ERROR_TYPE_ERROR,
360              _("Failed to serialize NS record with value `%s'\n"),
361              s);
362         return GNUNET_SYSERR;
363       }
364       *data_size = off;
365       *data = GNUNET_malloc (off);
366       memcpy (*data, nsbuf, off);
367       return GNUNET_OK;
368     }
369   case GNUNET_DNSPARSER_TYPE_CNAME:
370     {
371       char cnamebuf[256];
372       size_t off;
373
374       off = 0;
375       if (GNUNET_OK !=
376           GNUNET_DNSPARSER_builder_add_name (cnamebuf,
377                                              sizeof (cnamebuf),
378                                              &off,
379                                              s))
380       {
381         LOG (GNUNET_ERROR_TYPE_ERROR,
382              _("Failed to serialize CNAME record with value `%s'\n"),
383              s);
384         return GNUNET_SYSERR;
385       }
386       *data_size = off;
387       *data = GNUNET_malloc (off);
388       memcpy (*data, cnamebuf, off);
389       return GNUNET_OK;
390     }
391   case GNUNET_DNSPARSER_TYPE_SOA:
392     {
393       struct GNUNET_DNSPARSER_SoaRecord soa;
394       char soabuf[540];
395       char soa_rname[253 + 1];
396       char soa_mname[253 + 1];
397       unsigned int soa_serial;
398       unsigned int soa_refresh;
399       unsigned int soa_retry;
400       unsigned int soa_expire;
401       unsigned int soa_min;
402       size_t off;
403
404       if (7 != SSCANF (s,
405                        "rname=%253s mname=%253s %u,%u,%u,%u,%u",
406                        soa_rname, soa_mname,
407                        &soa_serial, &soa_refresh, &soa_retry, &soa_expire, &soa_min))
408       {
409         LOG (GNUNET_ERROR_TYPE_ERROR,
410              _("Unable to parse SOA record `%s'\n"),
411              s);
412         return GNUNET_SYSERR;
413       }
414       soa.mname = soa_mname;
415       soa.rname = soa_rname;
416       soa.serial = (uint32_t) soa_serial;
417       soa.refresh =(uint32_t)  soa_refresh;
418       soa.retry = (uint32_t) soa_retry;
419       soa.expire = (uint32_t) soa_expire;
420       soa.minimum_ttl = (uint32_t) soa_min;
421       off = 0;
422       if (GNUNET_OK !=
423           GNUNET_DNSPARSER_builder_add_soa (soabuf,
424                                             sizeof (soabuf),
425                                             &off,
426                                             &soa))
427       {
428         LOG (GNUNET_ERROR_TYPE_ERROR,
429              _("Failed to serialize SOA record with mname `%s' and rname `%s'\n"),
430              soa_mname,
431              soa_rname);
432         return GNUNET_SYSERR;
433       }
434       *data_size = off;
435       *data = GNUNET_malloc (off);
436       memcpy (*data, soabuf, off);
437       return GNUNET_OK;
438     }
439   case GNUNET_DNSPARSER_TYPE_PTR:
440     {
441       char ptrbuf[256];
442       size_t off;
443
444       off = 0;
445       if (GNUNET_OK !=
446           GNUNET_DNSPARSER_builder_add_name (ptrbuf,
447                                              sizeof (ptrbuf),
448                                              &off,
449                                              s))
450       {
451         LOG (GNUNET_ERROR_TYPE_ERROR,
452              _("Failed to serialize PTR record with value `%s'\n"),
453              s);
454         return GNUNET_SYSERR;
455       }
456       *data_size = off;
457       *data = GNUNET_malloc (off);
458       memcpy (*data, ptrbuf, off);
459       return GNUNET_OK;
460     }
461   case GNUNET_DNSPARSER_TYPE_MX:
462     {
463       struct GNUNET_DNSPARSER_MxRecord mx;
464       char mxbuf[258];
465       char mxhost[253 + 1];
466       uint16_t mx_pref;
467       size_t off;
468
469       if (2 != SSCANF(s, "%hu,%253s", &mx_pref, mxhost))
470       {
471         LOG (GNUNET_ERROR_TYPE_ERROR,
472              _("Unable to parse MX record `%s'\n"),
473              s);
474       return GNUNET_SYSERR;
475       }
476       mx.preference = mx_pref;
477       mx.mxhost = mxhost;
478       off = 0;
479
480       if (GNUNET_OK !=
481           GNUNET_DNSPARSER_builder_add_mx (mxbuf,
482                                            sizeof (mxbuf),
483                                            &off,
484                                            &mx))
485       {
486         LOG (GNUNET_ERROR_TYPE_ERROR,
487              _("Failed to serialize MX record with hostname `%s'\n"),
488              mxhost);
489         return GNUNET_SYSERR;
490       }
491       *data_size = off;
492       *data = GNUNET_malloc (off);
493       memcpy (*data, mxbuf, off);
494       return GNUNET_OK;
495     }
496   case GNUNET_DNSPARSER_TYPE_TXT:
497     *data = GNUNET_strdup (s);
498     *data_size = strlen (s);
499     return GNUNET_OK;
500   case GNUNET_DNSPARSER_TYPE_AAAA:
501     if (1 != inet_pton (AF_INET6, s, &value_aaaa))
502     {
503       LOG (GNUNET_ERROR_TYPE_ERROR,
504            _("Unable to parse IPv6 address `%s'\n"),
505            s);
506       return GNUNET_SYSERR;
507     }
508     *data = GNUNET_malloc (sizeof (struct in6_addr));
509     *data_size = sizeof (struct in6_addr);
510     memcpy (*data, &value_aaaa, sizeof (value_aaaa));
511     return GNUNET_OK;
512   case GNUNET_GNSRECORD_TYPE_PKEY:
513     if (GNUNET_OK !=
514         GNUNET_CRYPTO_ecdsa_public_key_from_string (s, strlen (s), &pkey))
515     {
516       LOG (GNUNET_ERROR_TYPE_ERROR,
517            _("Unable to parse PKEY record `%s'\n"),
518            s);
519       return GNUNET_SYSERR;
520     }
521     *data = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
522     memcpy (*data, &pkey, sizeof (pkey));
523     *data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
524     return GNUNET_OK;
525   case GNUNET_GNSRECORD_TYPE_PHONE:
526     {
527       struct GNUNET_CONVERSATION_PhoneRecord *pr;
528       unsigned int line;
529       const char *dash;
530       struct GNUNET_PeerIdentity peer;
531
532       if ( (NULL == (dash = strchr (s, '-'))) ||
533            (1 != sscanf (s, "%u-", &line)) ||
534            (GNUNET_OK !=
535             GNUNET_CRYPTO_eddsa_public_key_from_string (dash + 1,
536                                                            strlen (dash + 1),
537                                                            &peer.public_key)) )
538       {
539         LOG (GNUNET_ERROR_TYPE_ERROR,
540              _("Unable to parse PHONE record `%s'\n"),
541              s);
542         return GNUNET_SYSERR;
543       }
544       pr = GNUNET_new (struct GNUNET_CONVERSATION_PhoneRecord);
545       pr->version = htonl (0);
546       pr->line = htonl ((uint32_t) line);
547       pr->peer = peer;
548       *data = pr;
549       *data_size = sizeof (struct GNUNET_CONVERSATION_PhoneRecord);
550       return GNUNET_OK;
551     }
552   case GNUNET_GNSRECORD_TYPE_PSEU:
553     *data = GNUNET_strdup (s);
554     *data_size = strlen (s);
555     return GNUNET_OK;
556   case GNUNET_GNSRECORD_TYPE_LEHO:
557     *data = GNUNET_strdup (s);
558     *data_size = strlen (s);
559     return GNUNET_OK;
560   case GNUNET_GNSRECORD_TYPE_VPN:
561     if (3 != SSCANF (s,"%u %103s %253s",
562                      &proto, s_peer, s_serv))
563     {
564       LOG (GNUNET_ERROR_TYPE_ERROR,
565            _("Unable to parse VPN record string `%s'\n"),
566            s);
567       return GNUNET_SYSERR;
568     }
569     *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
570     *data = vpn = GNUNET_malloc (*data_size);
571     if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
572                                                                     strlen (s_peer),
573                                                                     &vpn->peer.public_key))
574     {
575       GNUNET_free (vpn);
576       *data_size = 0;
577       return GNUNET_SYSERR;
578     }
579     vpn->proto = htons ((uint16_t) proto);
580     strcpy ((char*)&vpn[1], s_serv);
581     return GNUNET_OK;
582   case GNUNET_GNSRECORD_TYPE_GNS2DNS:
583     {
584       char nsbuf[256];
585       size_t off;
586
587       off = 0;
588       if (GNUNET_OK !=
589           GNUNET_DNSPARSER_builder_add_name (nsbuf,
590                                              sizeof (nsbuf),
591                                              &off,
592                                              s))
593       {
594         LOG (GNUNET_ERROR_TYPE_ERROR,
595              _("Failed to serialize GNS2DNS record with value `%s'\n"),
596              s);
597         return GNUNET_SYSERR;
598       }
599       *data_size = off;
600       *data = GNUNET_malloc (off);
601       memcpy (*data, nsbuf, off);
602       return GNUNET_OK;
603     }
604   case GNUNET_DNSPARSER_TYPE_TLSA:
605     *data_size = sizeof (struct GNUNET_TUN_DnsTlsaRecord) + strlen (s) - 6;
606     *data = tlsa = GNUNET_malloc (*data_size);
607     if (4 != SSCANF (s, "%c %c %c %s",
608                      &tlsa->usage,
609                      &tlsa->selector,
610                      &tlsa->matching_type,
611                      (char*)&tlsa[1]))
612     {
613       LOG (GNUNET_ERROR_TYPE_ERROR,
614            _("Unable to parse TLSA record string `%s'\n"),
615            s);
616       *data_size = 0;
617       GNUNET_free (tlsa);
618       return GNUNET_SYSERR;
619     }
620     return GNUNET_OK;
621   default:
622     LOG (GNUNET_ERROR_TYPE_ERROR,
623          _("Unsupported record type %d\n"),
624          (int) type);
625     return GNUNET_SYSERR;
626   }
627 }
628
629
630 /**
631  * Mapping of record type numbers to human-readable
632  * record type names.
633  */
634 static struct {
635   const char *name;
636   uint32_t number;
637 } name_map[] = {
638   { "A", GNUNET_DNSPARSER_TYPE_A },
639   { "NS", GNUNET_DNSPARSER_TYPE_NS },
640   { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME },
641   { "SOA", GNUNET_DNSPARSER_TYPE_SOA },
642   { "PTR", GNUNET_DNSPARSER_TYPE_PTR },
643   { "MX", GNUNET_DNSPARSER_TYPE_MX },
644   { "TXT", GNUNET_DNSPARSER_TYPE_TXT },
645   { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA },
646   { "PKEY",  GNUNET_GNSRECORD_TYPE_PKEY },
647   { "PSEU",  GNUNET_GNSRECORD_TYPE_PSEU },
648   { "LEHO",  GNUNET_GNSRECORD_TYPE_LEHO },
649   { "VPN", GNUNET_GNSRECORD_TYPE_VPN },
650   { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS },
651   { "PHONE", GNUNET_GNSRECORD_TYPE_PHONE },
652   { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA },
653   { NULL, UINT32_MAX }
654 };
655
656
657 /**
658  * Convert a type name (i.e. "AAAA") to the corresponding number.
659  *
660  * @param dns_typename name to convert
661  * @return corresponding number, UINT32_MAX on error
662  */
663 uint32_t
664 GNUNET_GNSRECORD_typename_to_number (const char *dns_typename)
665 {
666   unsigned int i;
667
668   i=0;
669   while ( (name_map[i].name != NULL) &&
670           (0 != strcasecmp (dns_typename, name_map[i].name)) )
671     i++;
672   return name_map[i].number;
673 }
674
675
676 /**
677  * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
678  *
679  * @param type number of a type to convert
680  * @return corresponding typestring, NULL on error
681  */
682 const char *
683 GNUNET_GNSRECORD_number_to_typename (uint32_t type)
684 {
685   unsigned int i;
686
687   i=0;
688   while ( (name_map[i].name != NULL) &&
689           (type != name_map[i].number) )
690     i++;
691   return name_map[i].name;
692 }
693
694
695
696 /* end of namestore_common.c */