11638Srgrimes/* ldbuildid.c - Build Id support routines
21638Srgrimes   Copyright (C) 2013-2017 Free Software Foundation, Inc.
31638Srgrimes
41638Srgrimes   This file is part of the GNU Binutils.
51638Srgrimes
61638Srgrimes   This program is free software; you can redistribute it and/or modify
71638Srgrimes   it under the terms of the GNU General Public License as published by
81638Srgrimes   the Free Software Foundation; either version 3 of the License, or
91638Srgrimes   (at your option) any later version.
101638Srgrimes
111638Srgrimes   This program is distributed in the hope that it will be useful,
121638Srgrimes   but WITHOUT ANY WARRANTY; without even the implied warranty of
131638Srgrimes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141638Srgrimes   GNU General Public License for more details.
151638Srgrimes
161638Srgrimes   You should have received a copy of the GNU General Public License
171638Srgrimes   along with this program; if not, write to the Free Software
181638Srgrimes   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
191638Srgrimes   MA 02110-1301, USA.  */
201638Srgrimes
211638Srgrimes#include "sysdep.h"
221638Srgrimes#include "bfd.h"
231638Srgrimes#include "safe-ctype.h"
241638Srgrimes#include "md5.h"
251638Srgrimes#include "sha1.h"
261638Srgrimes#include "ldbuildid.h"
271638Srgrimes#ifdef __MINGW32__
281638Srgrimes#include <windows.h>
291638Srgrimes#include <rpcdce.h>
301638Srgrimes#endif
311638Srgrimes
321638Srgrimes#define streq(a,b)     strcmp ((a), (b)) == 0
3350476Speter#define strneq(a,b,n)  strncmp ((a), (b), (n)) == 0
341638Srgrimes
35279747Straszbfd_boolean
361638Srgrimesvalidate_build_id_style (const char *style)
371638Srgrimes{
381638Srgrimes  if ((streq (style, "md5")) || (streq (style, "sha1"))
391638Srgrimes      || (streq (style, "uuid")) || (strneq (style, "0x", 2)))
40107788Sru    return TRUE;
411638Srgrimes
42107788Sru  return FALSE;
43130582Sru}
4471895Sru
45107788Srubfd_size_type
4671895Srucompute_build_id_size (const char *style)
471638Srgrimes{
4871895Sru  if (streq (style, "md5") || streq (style, "uuid"))
4954338Sdcs    return 128 / 8;
5054338Sdcs
51130582Sru  if (streq (style, "sha1"))
5271895Sru    return 160 / 8;
5354338Sdcs
5454338Sdcs  if (strneq (style, "0x", 2))
55273660Sian    {
56273660Sian      bfd_size_type size = 0;
57273660Sian      /* ID is in string form (hex).  Count the bytes.  */
58273660Sian      const char *id = style + 2;
59273660Sian
60273660Sian      do
61273660Sian	{
62273660Sian	  if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
6371895Sru	    {
6465526Sobrien	      ++size;
65273660Sian	      id += 2;
6671895Sru	    }
6793959Smurray	  else if (*id == '-' || *id == ':')
6879727Sschweikh	    ++id;
6979727Sschweikh	  else
70273660Sian	    {
71273660Sian	      size = 0;
72273660Sian	      break;
73273660Sian	    }
7454338Sdcs	} while (*id != '\0');
7578824Snik      return size;
7678824Snik    }
7778824Snik
7878824Snik  return 0;
7978824Snik}
8078824Snik
8178824Snikstatic unsigned char
8279797Snikread_hex (const char xdigit)
8371895Sru{
84138977Sjkoshy  if (ISDIGIT (xdigit))
85138977Sjkoshy    return xdigit - '0';
861638Srgrimes
87138977Sjkoshy  if (ISUPPER (xdigit))
8879727Sschweikh    return xdigit - 'A' + 0xa;
891638Srgrimes
901638Srgrimes  if (ISLOWER (xdigit))
911638Srgrimes    return xdigit - 'a' + 0xa;
92138977Sjkoshy
93138977Sjkoshy  abort ();
941638Srgrimes  return 0;
9571895Sru}
9679727Sschweikh
971638Srgrimesbfd_boolean
98157693Sbrueffergenerate_build_id (bfd *abfd,
9971895Sru		   const char *style,
10047597Snik		   checksum_fn checksum_contents,
10147597Snik		   unsigned char *id_bits,
10247597Snik		   int size ATTRIBUTE_UNUSED)
103157693Sbrueffer{
104157693Sbrueffer  if (streq (style, "md5"))
10571895Sru    {
10623524Swosch      struct md5_ctx ctx;
10723524Swosch
10823524Swosch      md5_init_ctx (&ctx);
10971895Sru      if (!(*checksum_contents) (abfd, (sum_fn) &md5_process_bytes, &ctx))
11078824Snik	return FALSE;
11179727Sschweikh      md5_finish_ctx (&ctx, id_bits);
1121638Srgrimes    }
1131638Srgrimes  else if (streq (style, "sha1"))
11415135Smpp    {
11593959Smurray      struct sha1_ctx ctx;
11693959Smurray
117162286Sjoel      sha1_init_ctx (&ctx);
11871895Sru      if (!(*checksum_contents) (abfd, (sum_fn) &sha1_process_bytes, &ctx))
11947597Snik	return FALSE;
12047597Snik      sha1_finish_ctx (&ctx, id_bits);
12147597Snik    }
12247597Snik  else if (streq (style, "uuid"))
123157693Sbrueffer    {
124157693Sbrueffer#ifndef __MINGW32__
125157693Sbrueffer      int n;
126157693Sbrueffer      int fd = open ("/dev/urandom", O_RDONLY);
127157693Sbrueffer
128157693Sbrueffer      if (fd < 0)
129157693Sbrueffer	return FALSE;
130157693Sbrueffer      n = read (fd, id_bits, size);
13171895Sru      close (fd);
13223524Swosch      if (n < size)
13379727Sschweikh	return FALSE;
13423524Swosch#else /* __MINGW32__ */
135157693Sbrueffer      typedef RPC_STATUS (RPC_ENTRY * UuidCreateFn) (UUID *);
136157693Sbrueffer      UUID          uuid;
137157693Sbrueffer      UuidCreateFn  uuid_create = 0;
138157693Sbrueffer      HMODULE       rpc_library = LoadLibrary ("rpcrt4.dll");
13971895Sru
14056900Skris      if (!rpc_library)
1411638Srgrimes	return FALSE;
142122859Sgordon      uuid_create = (UuidCreateFn) GetProcAddress (rpc_library, "UuidCreate");
143122859Sgordon      if (!uuid_create)
144122859Sgordon	{
145122859Sgordon	  FreeLibrary (rpc_library);
146122859Sgordon	  return FALSE;
147129480Spjd	}
148130582Sru
149129480Spjd      if (uuid_create (&uuid) != RPC_S_OK)
150129491Spjd	{
151129480Spjd	  FreeLibrary (rpc_library);
152129480Spjd	  return FALSE;
153129480Spjd	}
154122859Sgordon      FreeLibrary (rpc_library);
155130845Smpp      memcpy (id_bits, &uuid,
156122859Sgordon	      (size_t) size < sizeof (UUID) ? (size_t) size : sizeof (UUID));
157122859Sgordon#endif /* __MINGW32__ */
158122859Sgordon    }
159158409Smarcus  else if (strneq (style, "0x", 2))
160158409Smarcus    {
161158409Smarcus      /* ID is in string form (hex).  Convert to bits.  */
162158409Smarcus      const char *id = style + 2;
16371895Sru      size_t n = 0;
1641638Srgrimes
1651638Srgrimes      do
166279747Strasz	{
167279747Strasz	  if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
168279747Strasz	    {
169279747Strasz	      id_bits[n] = read_hex (*id++) << 4;
17071895Sru	      id_bits[n++] |= read_hex (*id++);
171107788Sru	    }
17223524Swosch	  else if (*id == '-' || *id == ':')
173164482Srodrigc	    ++id;
174118647Ssimon	  else
175118647Ssimon	    abort ();		/* Should have been validated earlier.  */
176118647Ssimon	}
177118647Ssimon      while (*id != '\0');
17871895Sru    }
17923524Swosch  else
18071895Sru    abort ();			/* Should have been validated earlier.  */
1811638Srgrimes
1821638Srgrimes  return TRUE;
18379727Sschweikh}
18485030Smurray