fix: prevent segfault if malicious server sends 1 GB of data through ftpNLST.
[platform/upstream/rpm.git] / rpmio / rpmio_internal.h
1 #ifndef H_RPMIO_INTERNAL
2 #define H_RPMIO_INTERNAL
3
4 /** \ingroup rpmio
5  * \file rpmio/rpmio_internal.h
6  */
7
8
9 #include <rpmio.h>
10 #include <rpmurl.h>
11
12 #include <beecrypt/types.h>
13 #include <rpmpgp.h>
14 #include <rpmsw.h>
15
16 /* Drag in the beecrypt includes. */
17 #include <beecrypt/beecrypt.h>
18 #include <beecrypt/base64.h>
19 #include <beecrypt/dsa.h>
20 #include <beecrypt/endianness.h>
21 #include <beecrypt/md5.h>
22 #include <beecrypt/mp32.h>
23 #include <beecrypt/rsa.h>
24 #include <beecrypt/rsapk.h>
25 #include <beecrypt/sha1.h>
26
27 /** \ingroup rpmio
28  * Values parsed from OpenPGP signature/pubkey packet(s).
29  */
30 struct pgpDigParams_s {
31 /*@only@*/ /*@null@*/
32     const char * userid;
33 /*@only@*/ /*@null@*/
34     const byte * hash;
35     const char * params[4];
36     byte tag;
37
38     byte version;               /*!< version number. */
39     byte time[4];               /*!< time that the key was created. */
40     byte pubkey_algo;           /*!< public key algorithm. */
41
42     byte hash_algo;
43     byte sigtype;
44     byte hashlen;
45     byte signhash16[2];
46     byte signid[8];
47     byte saved;
48 #define PGPDIG_SAVED_TIME       (1 << 0)
49 #define PGPDIG_SAVED_ID         (1 << 1)
50
51 };
52
53 /** \ingroup rpmio
54  * Container for values parsed from an OpenPGP signature and public key.
55  */
56 struct pgpDig_s {
57     struct pgpDigParams_s signature;
58     struct pgpDigParams_s pubkey;
59
60     size_t nbytes;              /*!< No. bytes of plain text. */
61
62 /*@only@*/ /*@null@*/
63     DIGEST_CTX sha1ctx;         /*!< (dsa) sha1 hash context. */
64 /*@only@*/ /*@null@*/
65     DIGEST_CTX hdrsha1ctx;      /*!< (dsa) header sha1 hash context. */
66 /*@only@*/ /*@null@*/
67     void * sha1;                /*!< (dsa) V3 signature hash. */
68     size_t sha1len;             /*!< (dsa) V3 signature hash length. */
69
70 /*@only@*/ /*@null@*/
71     DIGEST_CTX md5ctx;          /*!< (rsa) md5 hash context. */
72 #ifdef  NOTYET
73 /*@only@*/ /*@null@*/
74     DIGEST_CTX hdrmd5ctx;       /*!< (rsa) header md5 hash context. */
75 #endif
76 /*@only@*/ /*@null@*/
77     void * md5;                 /*!< (rsa) V3 signature hash. */
78     size_t md5len;              /*!< (rsa) V3 signature hash length. */
79
80     /* DSA parameters. */
81     mp32barrett p;
82     mp32barrett q;
83     mp32number g;
84     mp32number y;
85     mp32number hm;
86     mp32number r;
87     mp32number s;
88
89     /* RSA parameters. */
90     rsapk rsa_pk;
91     mp32number m;
92     mp32number c;
93     mp32number rsahm;
94 };
95
96 /** \ingroup rpmio
97  */
98 typedef struct _FDSTACK_s {
99     FDIO_t              io;
100 /*@dependent@*/ void *  fp;
101     int                 fdno;
102 } FDSTACK_t;
103
104 /** \ingroup rpmio
105  * Identify per-desciptor I/O operation statistics.
106  */
107 typedef enum fdOpX_e {
108     FDSTAT_READ         = 0,    /*!< Read statistics index. */
109     FDSTAT_WRITE        = 1,    /*!< Write statistics index. */
110     FDSTAT_SEEK         = 2,    /*!< Seek statistics index. */
111     FDSTAT_CLOSE        = 3,    /*!< Close statistics index */
112     FDSTAT_DIGEST       = 4,    /*!< Digest statistics index. */
113     FDSTAT_MAX          = 5
114 } fdOpX;
115
116 /** \ingroup rpmio
117  * Cumulative statistics for a descriptor.
118  */
119 typedef /*@abstract@*/ struct {
120     struct rpmop_s      ops[FDSTAT_MAX];        /*!< Cumulative statistics. */
121 } * FDSTAT_t;
122
123 /** \ingroup rpmio
124  */
125 typedef struct _FDDIGEST_s {
126     pgpHashAlgo         hashalgo;
127     DIGEST_CTX          hashctx;
128 } * FDDIGEST_t;
129
130 /** \ingroup rpmio
131  * The FD_t File Handle data structure.
132  */
133 struct _FD_s {
134 /*@refs@*/
135     int         nrefs;
136     int         flags;
137 #define RPMIO_DEBUG_IO          0x40000000
138 #define RPMIO_DEBUG_REFS        0x20000000
139     int         magic;
140 #define FDMAGIC                 0x04463138
141     int         nfps;
142     FDSTACK_t   fps[8];
143     int         urlType;        /* ufdio: */
144
145 /*@dependent@*/
146     void *      url;            /* ufdio: URL info */
147     int         rd_timeoutsecs; /* ufdRead: per FD_t timer */
148     ssize_t     bytesRemain;    /* ufdio: */
149     ssize_t     contentLength;  /* ufdio: */
150     int         persist;        /* ufdio: */
151     int         wr_chunked;     /* ufdio: */
152
153     int         syserrno;       /* last system errno encountered */
154 /*@observer@*/
155     const void *errcookie;      /* gzdio/bzdio/ufdio: */
156
157     FDSTAT_t    stats;          /* I/O statistics */
158
159     int         ndigests;
160 #define FDDIGEST_MAX    4
161     struct _FDDIGEST_s  digests[FDDIGEST_MAX];
162
163     int         ftpFileDoneNeeded; /* ufdio: (FTP) */
164     unsigned int firstFree;     /* fadio: */
165     long int    fileSize;       /* fadio: */
166     long int    fd_cpioPos;     /* cpio: */
167 };
168 /*@access FD_t@*/
169
170 #define FDSANE(fd)      assert(fd && fd->magic == FDMAGIC)
171
172 /*@-redecl@*/
173 /*@unchecked@*/
174 extern int _rpmio_debug;
175 /*@=redecl@*/
176
177 /*@-redecl@*/
178 /*@unchecked@*/
179 extern int _ftp_debug;
180 /*@=redecl@*/
181
182 #define DBG(_f, _m, _x) \
183     if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) & (_m)) fprintf _x
184
185 #if defined(__LCLINT__XXX)
186 #define DBGIO(_f, _x)
187 #define DBGREFS(_f, _x)
188 #else
189 #define DBGIO(_f, _x)   DBG((_f), RPMIO_DEBUG_IO, _x)
190 #define DBGREFS(_f, _x) DBG((_f), RPMIO_DEBUG_REFS, _x)
191 #endif
192
193 #ifdef __cplusplus
194 extern "C" {
195 #endif
196
197 /** \ingroup rpmio
198  */
199 int fdFgets(FD_t fd, char * buf, size_t len)
200         /*@globals errno, fileSystem @*/
201         /*@modifies *buf, fd, errno, fileSystem @*/;
202
203 /** \ingroup rpmio
204  */
205 /*@null@*/ FD_t ftpOpen(const char *url, /*@unused@*/ int flags,
206                 /*@unused@*/ mode_t mode, /*@out@*/ urlinfo *uret)
207         /*@globals fileSystem, internalState @*/
208         /*@modifies *uret, fileSystem, internalState @*/;
209
210 /** \ingroup rpmio
211  */
212 int ftpReq(FD_t data, const char * ftpCmd, const char * ftpArg)
213         /*@globals fileSystem, internalState @*/
214         /*@modifies data, fileSystem, internalState @*/;
215
216 /** \ingroup rpmio
217  */
218 int ftpCmd(const char * cmd, const char * url, const char * arg2)
219         /*@globals fileSystem, internalState @*/
220         /*@modifies fileSystem, internalState @*/;
221
222 /** \ingroup rpmio
223  */
224 int ufdClose( /*@only@*/ void * cookie)
225         /*@globals fileSystem, internalState @*/
226         /*@modifies cookie, fileSystem, internalState @*/;
227
228 /** \ingroup rpmio
229  */
230 /*@unused@*/ static inline
231 /*@null@*/ FDIO_t fdGetIo(FD_t fd)
232         /*@*/
233 {
234     FDSANE(fd);
235 /*@-boundsread@*/
236     return fd->fps[fd->nfps].io;
237 /*@=boundsread@*/
238 }
239
240 /** \ingroup rpmio
241  */
242 /*@-nullstate@*/ /* FIX: io may be NULL */
243 /*@unused@*/ static inline
244 void fdSetIo(FD_t fd, /*@kept@*/ /*@null@*/ FDIO_t io)
245         /*@modifies fd @*/
246 {
247     FDSANE(fd);
248 /*@-boundswrite@*/
249     /*@-assignexpose@*/
250     fd->fps[fd->nfps].io = io;
251     /*@=assignexpose@*/
252 /*@=boundswrite@*/
253 }
254 /*@=nullstate@*/
255
256 /** \ingroup rpmio
257  */
258 /*@unused@*/ static inline
259 /*@exposed@*/ /*@dependent@*/ /*@null@*/ FILE * fdGetFILE(FD_t fd)
260         /*@*/
261 {
262     FDSANE(fd);
263 /*@-boundsread@*/
264     /*@+voidabstract@*/
265     return ((FILE *)fd->fps[fd->nfps].fp);
266     /*@=voidabstract@*/
267 /*@=boundsread@*/
268 }
269
270 /** \ingroup rpmio
271  */
272 /*@unused@*/ static inline
273 /*@exposed@*/ /*@dependent@*/ /*@null@*/ void * fdGetFp(FD_t fd)
274         /*@*/
275 {
276     FDSANE(fd);
277 /*@-boundsread@*/
278     return fd->fps[fd->nfps].fp;
279 /*@=boundsread@*/
280 }
281
282 /** \ingroup rpmio
283  */
284 /*@-nullstate@*/ /* FIX: fp may be NULL */
285 /*@unused@*/ static inline
286 void fdSetFp(FD_t fd, /*@kept@*/ /*@null@*/ void * fp)
287         /*@modifies fd @*/
288 {
289     FDSANE(fd);
290 /*@-boundswrite@*/
291     /*@-assignexpose@*/
292     fd->fps[fd->nfps].fp = fp;
293     /*@=assignexpose@*/
294 /*@=boundswrite@*/
295 }
296 /*@=nullstate@*/
297
298 /** \ingroup rpmio
299  */
300 /*@unused@*/ static inline
301 int fdGetFdno(FD_t fd)
302         /*@*/
303 {
304     FDSANE(fd);
305 /*@-boundsread@*/
306     return fd->fps[fd->nfps].fdno;
307 /*@=boundsread@*/
308 }
309
310 /** \ingroup rpmio
311  */
312 /*@unused@*/ static inline
313 void fdSetFdno(FD_t fd, int fdno)
314         /*@modifies fd @*/
315 {
316     FDSANE(fd);
317 /*@-boundswrite@*/
318     fd->fps[fd->nfps].fdno = fdno;
319 /*@=boundswrite@*/
320 }
321
322 /** \ingroup rpmio
323  */
324 /*@unused@*/ static inline
325 void fdSetContentLength(FD_t fd, ssize_t contentLength)
326         /*@modifies fd @*/
327 {
328     FDSANE(fd);
329     fd->contentLength = fd->bytesRemain = contentLength;
330 }
331
332 /** \ingroup rpmio
333  */
334 /*@unused@*/ static inline
335 void fdPush(FD_t fd, FDIO_t io, void * fp, int fdno)
336         /*@modifies fd @*/
337 {
338     FDSANE(fd);
339     if (fd->nfps >= (sizeof(fd->fps)/sizeof(fd->fps[0]) - 1))
340         return;
341     fd->nfps++;
342     fdSetIo(fd, io);
343     fdSetFp(fd, fp);
344     fdSetFdno(fd, fdno);
345 }
346
347 /** \ingroup rpmio
348  */
349 /*@unused@*/ static inline
350 void fdPop(FD_t fd)
351         /*@modifies fd @*/
352 {
353     FDSANE(fd);
354     if (fd->nfps < 0) return;
355     fdSetIo(fd, NULL);
356     fdSetFp(fd, NULL);
357     fdSetFdno(fd, -1);
358     fd->nfps--;
359 }
360
361 /** \ingroup rpmio
362  */
363 /*@unused@*/ static inline /*@null@*/
364 rpmop fdstat_op(/*@null@*/ FD_t fd, fdOpX opx)
365         /*@*/
366 {
367     rpmop op = NULL;
368
369 /*@-boundsread@*/
370     if (fd != NULL && fd->stats != NULL && opx >= 0 && opx < FDSTAT_MAX)
371         op = fd->stats->ops + opx;
372 /*@=boundsread@*/
373     return op;
374 }
375
376 /** \ingroup rpmio
377  */
378 /*@unused@*/ static inline
379 void fdstat_enter(/*@null@*/ FD_t fd, int opx)
380         /*@globals internalState @*/
381         /*@modifies internalState @*/
382 {
383     if (fd == NULL) return;
384     if (fd->stats != NULL)
385         (void) rpmswEnter(fdstat_op(fd, opx), 0);
386 }
387
388 /** \ingroup rpmio
389  */
390 /*@unused@*/ static inline
391 void fdstat_exit(/*@null@*/ FD_t fd, int opx, ssize_t rc)
392         /*@globals internalState @*/
393         /*@modifies fd, internalState @*/
394 {
395     if (fd == NULL) return;
396     if (rc == -1)
397         fd->syserrno = errno;
398     else if (rc > 0 && fd->bytesRemain > 0)
399         fd->bytesRemain -= rc;
400     if (fd->stats != NULL)
401         (void) rpmswExit(fdstat_op(fd, opx), rc);
402 }
403
404 /** \ingroup rpmio
405  */
406 /*@-boundsread@*/
407 /*@unused@*/ static inline
408 void fdstat_print(/*@null@*/ FD_t fd, const char * msg, FILE * fp)
409         /*@globals fileSystem @*/
410         /*@modifies *fp, fileSystem @*/
411 {
412     static int usec_scale = (1000*1000);
413     int opx;
414
415     if (fd == NULL || fd->stats == NULL) return;
416     for (opx = 0; opx < 4; opx++) {
417         rpmop op = &fd->stats->ops[opx];
418         if (op->count <= 0) continue;
419         switch (opx) {
420         case FDSTAT_READ:
421             if (msg) fprintf(fp, "%s:", msg);
422             fprintf(fp, "%8d reads, %8ld total bytes in %d.%06d secs\n",
423                 op->count, (long)op->bytes,
424                 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
425             /*@switchbreak@*/ break;
426         case FDSTAT_WRITE:
427             if (msg) fprintf(fp, "%s:", msg);
428             fprintf(fp, "%8d writes, %8ld total bytes in %d.%06d secs\n",
429                 op->count, (long)op->bytes,
430                 (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
431             /*@switchbreak@*/ break;
432         case FDSTAT_SEEK:
433             /*@switchbreak@*/ break;
434         case FDSTAT_CLOSE:
435             /*@switchbreak@*/ break;
436         }
437     }
438 }
439 /*@=boundsread@*/
440
441 /** \ingroup rpmio
442  */
443 /*@unused@*/ static inline
444 void fdSetSyserrno(FD_t fd, int syserrno, /*@kept@*/ const void * errcookie)
445         /*@modifies fd @*/
446 {
447     FDSANE(fd);
448     fd->syserrno = syserrno;
449     /*@-assignexpose@*/
450     fd->errcookie = errcookie;
451     /*@=assignexpose@*/
452 }
453
454 /** \ingroup rpmio
455  */
456 /*@unused@*/ static inline
457 int fdGetRdTimeoutSecs(FD_t fd)
458         /*@*/
459 {
460     FDSANE(fd);
461     return fd->rd_timeoutsecs;
462 }
463
464 /** \ingroup rpmio
465  */
466 /*@unused@*/ static inline
467 long int fdGetCpioPos(FD_t fd)
468         /*@*/
469 {
470     FDSANE(fd);
471     return fd->fd_cpioPos;
472 }
473
474 /** \ingroup rpmio
475  */
476 /*@unused@*/ static inline
477 void fdSetCpioPos(FD_t fd, long int cpioPos)
478         /*@modifies fd @*/
479 {
480     FDSANE(fd);
481     fd->fd_cpioPos = cpioPos;
482 }
483
484 /** \ingroup rpmio
485  */
486 /*@mayexit@*/ /*@unused@*/ static inline
487 FD_t c2f(/*@null@*/ void * cookie)
488         /*@*/
489 {
490     /*@-castexpose@*/
491     FD_t fd = (FD_t) cookie;
492     /*@=castexpose@*/
493     FDSANE(fd);
494     /*@-refcounttrans -retalias@*/ return fd; /*@=refcounttrans =retalias@*/
495 }
496
497 /** \ingroup rpmio
498  * Attach digest to fd.
499  */
500 /*@unused@*/ static inline
501 void fdInitDigest(FD_t fd, pgpHashAlgo hashalgo, int flags)
502         /*@globals internalState @*/
503         /*@modifies fd, internalState @*/
504 {
505     FDDIGEST_t fddig = fd->digests + fd->ndigests;
506     if (fddig != (fd->digests + FDDIGEST_MAX)) {
507         fd->ndigests++;
508         fddig->hashalgo = hashalgo;
509         fdstat_enter(fd, FDSTAT_DIGEST);
510         fddig->hashctx = rpmDigestInit(hashalgo, flags);
511         fdstat_exit(fd, FDSTAT_DIGEST, 0);
512     }
513 }
514
515 /** \ingroup rpmio
516  * Update digest(s) attached to fd.
517  */
518 /*@unused@*/ static inline
519 void fdUpdateDigests(FD_t fd, const unsigned char * buf, ssize_t buflen)
520         /*@globals internalState @*/
521         /*@modifies fd, internalState @*/
522 {
523     int i;
524
525     if (buf != NULL && buflen > 0)
526     for (i = fd->ndigests - 1; i >= 0; i--) {
527         FDDIGEST_t fddig = fd->digests + i;
528         if (fddig->hashctx == NULL)
529             continue;
530         fdstat_enter(fd, FDSTAT_DIGEST);
531         (void) rpmDigestUpdate(fddig->hashctx, buf, buflen);
532         fdstat_exit(fd, FDSTAT_DIGEST, buflen);
533     }
534 }
535
536 /** \ingroup rpmio
537  */
538 /*@unused@*/ static inline
539 void fdFiniDigest(FD_t fd, pgpHashAlgo hashalgo,
540                 /*@null@*/ /*@out@*/ void ** datap,
541                 /*@null@*/ /*@out@*/ size_t * lenp,
542                 int asAscii)
543         /*@globals internalState @*/
544         /*@modifies fd, *datap, *lenp, internalState @*/
545 {
546     int imax = -1;
547     int i;
548
549     for (i = fd->ndigests - 1; i >= 0; i--) {
550         FDDIGEST_t fddig = fd->digests + i;
551         if (fddig->hashctx == NULL)
552             continue;
553         if (i > imax) imax = i;
554         if (fddig->hashalgo != hashalgo)
555             continue;
556         fdstat_enter(fd, FDSTAT_DIGEST);
557         (void) rpmDigestFinal(fddig->hashctx, datap, lenp, asAscii);
558         fdstat_exit(fd, FDSTAT_DIGEST, 0);
559         fddig->hashctx = NULL;
560         break;
561     }
562 /*@-boundswrite@*/
563     if (i < 0) {
564         if (datap) *datap = NULL;
565         if (lenp) *lenp = 0;
566     }
567 /*@=boundswrite@*/
568
569     fd->ndigests = imax;
570     if (i < imax)
571         fd->ndigests++;         /* convert index to count */
572 }
573
574 /*@-shadow@*/
575 /** \ingroup rpmio
576  */
577 /*@unused@*/ static inline
578 int fdFileno(/*@null@*/ void * cookie)
579         /*@*/
580 {
581     FD_t fd;
582     if (cookie == NULL) return -2;
583     fd = c2f(cookie);
584 /*@-boundsread@*/
585     return fd->fps[0].fdno;
586 /*@=boundsread@*/
587 }
588 /*@=shadow@*/
589
590 /**
591  * Read an entire file into a buffer.
592  * @param fn            file name to read
593  * @retval *bp          (malloc'd) buffer address
594  * @retval *blenp       (malloc'd) buffer length
595  * @return              0 on success
596  */
597 int rpmioSlurp(const char * fn,
598                 /*@out@*/ const unsigned char ** bp, /*@out@*/ ssize_t * blenp)
599         /*@globals fileSystem, internalState @*/
600         /*@modifies *bp, *blenp, fileSystem, internalState @*/;
601
602 #ifdef __cplusplus
603 }
604 #endif
605
606 #endif  /* H_RPMIO_INTERNAL */