Further streamline & sanitize lead handling
[platform/upstream/rpm.git] / lib / rpmlead.c
1 /** \ingroup lead
2  * \file lib/rpmlead.c
3  */
4
5 #include "system.h"
6
7 #include <errno.h>
8 #include <netinet/in.h>
9
10 #include <rpm/rpmlib.h>         /* rpmGetOs/ArchInfo() */
11 #include <rpm/rpmlog.h>
12 #include <rpm/rpmstring.h>
13
14 #include "lib/signature.h"
15 #include "lib/rpmlead.h"
16
17 #include "debug.h"
18
19 static unsigned char const lead_magic[] = {
20     RPMLEAD_MAGIC0, RPMLEAD_MAGIC1, RPMLEAD_MAGIC2, RPMLEAD_MAGIC3
21 };
22
23 /** \ingroup lead
24  * The lead data structure.
25  * The lead needs to be 8 byte aligned.
26  * @deprecated The lead (except for signature_type) is legacy.
27  * @todo Don't use any information from lead.
28  */
29 struct rpmlead_s {
30     unsigned char magic[4];
31     unsigned char major;
32     unsigned char minor;
33     short type;
34     short archnum;
35     char name[66];
36     short osnum;
37     short signature_type;       /*!< Signature header type (RPMSIG_HEADERSIG) */
38     char reserved[16];      /*!< Pad to 96 bytes -- 8 byte aligned! */
39 };
40
41 rpmlead rpmLeadFromHeader(Header h)
42 {
43     rpmlead l = NULL;
44
45     if (h != NULL) {
46         int archnum, osnum;
47         char * nevr = headerGetAsString(h, RPMTAG_NEVR);
48
49         /* FIXME: should grab these from header instead (RhBug:717898) */
50         rpmGetArchInfo(NULL, &archnum);
51         rpmGetOsInfo(NULL, &osnum);
52
53         l = xcalloc(1, sizeof(*l));
54         l->major = 3;
55         l->minor = 0;
56         l->archnum = archnum;
57         l->osnum = osnum;
58         l->signature_type = RPMSIGTYPE_HEADERSIG;
59         l->type = (headerIsSource(h) ? 1 : 0);
60
61         memcpy(l->magic, lead_magic, sizeof(l->magic));
62         rstrlcpy(l->name, nevr, sizeof(l->name));
63
64         free(nevr);
65     }
66
67     return l;
68 }
69
70 rpmlead rpmLeadFree(rpmlead lead)
71 {
72     free(lead);
73     return NULL;
74 }
75
76 /* The lead needs to be 8 byte aligned */
77 rpmRC rpmLeadWrite(FD_t fd, rpmlead lead)
78 {
79     rpmRC rc = RPMRC_FAIL;
80
81     if (lead != NULL) {
82         struct rpmlead_s l;
83         memcpy(&l, lead, sizeof(l));
84         
85         l.type = htons(lead->type);
86         l.archnum = htons(lead->archnum);
87         l.osnum = htons(lead->osnum);
88         l.signature_type = htons(lead->signature_type);
89             
90         if (Fwrite(&l, 1, sizeof(l), fd) == sizeof(l))
91             rc = RPMRC_OK;
92     }
93     return rc;
94 }
95
96 static rpmRC rpmLeadCheck(rpmlead lead, char **msg)
97 {
98     if (memcmp(lead->magic, lead_magic, sizeof(lead_magic))) {
99         *msg = xstrdup(_("not an rpm package"));
100         return RPMRC_NOTFOUND;
101     }
102     if (lead->signature_type != RPMSIGTYPE_HEADERSIG) {
103         *msg = xstrdup(_("illegal signature type"));
104         return RPMRC_FAIL;
105     }
106     if (lead->major < 3 || lead->major > 4) {
107         *msg = xstrdup(_("unsupported RPM package version"));
108         return RPMRC_FAIL;
109     }
110     return RPMRC_OK;
111 }
112
113 rpmRC rpmLeadRead(FD_t fd, rpmlead *lead, int *type, char **emsg)
114 {
115     rpmRC rc = RPMRC_OK;
116     struct rpmlead_s l;
117     char *err = NULL;
118
119     memset(&l, 0, sizeof(l));
120     if (Fread(&l, 1, sizeof(l), fd) != sizeof(l)) {
121         if (Ferror(fd)) {
122             rasprintf(&err, _("read failed: %s (%d)\n"), Fstrerror(fd), errno);
123             rc = RPMRC_FAIL;
124         } else {
125             err = xstrdup(_("not an rpm package\n"));
126             rc = RPMRC_NOTFOUND;
127         }
128     } else {
129         l.type = ntohs(l.type);
130         l.archnum = ntohs(l.archnum);
131         l.osnum = ntohs(l.osnum);
132         l.signature_type = ntohs(l.signature_type);
133         rc = rpmLeadCheck(&l, &err);
134     }
135
136     if (rc == RPMRC_OK) {
137         if (lead != NULL) {
138             *lead = xmalloc(sizeof(l));
139             memcpy(*lead, &l, sizeof(l));
140         }
141         if (type != NULL)
142             *type = l.type;
143     } else {
144         if (emsg != NULL)
145             *emsg = err;
146         else
147             free(err);
148     }
149
150     return rc;
151 }