1 /*****************************************************************************
2  *  Written by Chris Dunlap <cdunlap@llnl.gov>.
3  *  Copyright (C) 2007-2020 Lawrence Livermore National Security, LLC.
4  *  Copyright (C) 2002-2007 The Regents of the University of California.
5  *  UCRL-CODE-155910.
6  *
7  *  This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE).
8  *  For details, see <https://dun.github.io/munge/>.
9  *
10  *  MUNGE is free software: you can redistribute it and/or modify it under
11  *  the terms of the GNU General Public License as published by the Free
12  *  Software Foundation, either version 3 of the License, or (at your option)
13  *  any later version.  Additionally for the MUNGE library (libmunge), you
14  *  can redistribute it and/or modify it under the terms of the GNU Lesser
15  *  General Public License as published by the Free Software Foundation,
16  *  either version 3 of the License, or (at your option) any later version.
17  *
18  *  MUNGE is distributed in the hope that it will be useful, but WITHOUT
19  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21  *  and GNU Lesser General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  and GNU Lesser General Public License along with MUNGE.  If not, see
25  *  <http://www.gnu.org/licenses/>.
26  *****************************************************************************/
27 
28 
29 #if HAVE_CONFIG_H
30 #  include "config.h"
31 #endif /* HAVE_CONFIG_H */
32 
33 #include <assert.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <munge.h>
40 #include "log.h"
41 #include "munge_defs.h"
42 
43 
44 #define INITIAL_BUFFER_SIZE     4096
45 #define MAXIMUM_BUFFER_SIZE     MUNGE_MAXIMUM_REQ_LEN
46 /*
47  *  MUNGE_MAXIMUM_REQ_LEN (in munge_defs.h) specifies the maximum size of a
48  *    request message transmitted over the unix domain socket.  Since messages
49  *    greater than this length will be rejected, MAXIMUM_BUFFER_SIZE is used to
50  *    limit the size of the memory allocation for bufmem.
51  */
52 
53 
54 void
read_data_from_file(FILE * fp,void ** buf,int * len)55 read_data_from_file (FILE *fp, void **buf, int *len)
56 {
57     unsigned char *bufmem;              /* base ptr to buffer memory         */
58     unsigned char *bufptr;              /* current ptr to unused bufmem      */
59     unsigned char *buftmp;              /* tmp ptr to bufmem for realloc()   */
60     size_t         bufsiz;              /* size allocated for bufmem         */
61     size_t         buflen;              /* num bytes of unused bufmem        */
62     size_t         bufuse;              /* num bytes of used bufmem          */
63     size_t         n;
64 
65     assert (fp != NULL);
66     assert (buf != NULL);
67     assert (len != NULL);
68 
69     bufsiz = INITIAL_BUFFER_SIZE;
70     bufmem = bufptr = malloc (bufsiz);
71     if (bufmem == NULL) {
72         log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
73             "Failed to allocate %lu bytes", bufsiz);
74     }
75     buflen = bufsiz;
76 
77     /*  Since this reads from a standard I/O stream, there is no guarantee that
78      *    the stream provides random access (e.g., when reading from a pipe).
79      *    As such, it cannot rely on seeking to the end of the stream to
80      *    determine the file length before seeking back to the beginning to
81      *    start reading.  Consequently, this routine realloc()s the buffer to
82      *    grow it as needed while reading from the fp steam.
83      */
84     for (;;) {
85         n = fread (bufptr, 1, buflen, fp);
86         bufptr += n;
87         buflen -= n;
88         if (buflen > 0) {
89             if (feof (fp)) {
90                 break;
91             }
92             else if (ferror (fp)) {
93                 log_err (EMUNGE_SNAFU, LOG_ERR,
94                     "Failed to read from file");
95             }
96             else {
97                 log_err (EMUNGE_SNAFU, LOG_ERR,
98                     "Failed to read from file: Unexpected short count");
99             }
100         }
101         assert (buflen == 0);
102         assert (bufsiz == bufptr - bufmem);
103         bufuse = bufsiz;
104         bufsiz *= 2;
105         if (bufsiz > MAXIMUM_BUFFER_SIZE) {
106             free (bufmem);
107             log_errno (EMUNGE_SNAFU, LOG_ERR,
108                 "Exceeded maximum memory allocation");
109         }
110         buftmp = realloc (bufmem, bufsiz);
111         if (buftmp == NULL) {
112             free (bufmem);
113             log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
114                 "Failed to allocate %lu bytes", bufsiz);
115         }
116         buflen = bufsiz - bufuse;
117         bufptr = buftmp + bufuse;
118         bufmem = buftmp;
119     }
120     n = bufptr - bufmem;
121     if (n == 0) {
122         free (bufmem);
123         *buf = NULL;
124         *len = 0;
125         return;
126     }
127     /*  If the fp has exactly 'len' bytes remaining, fread (ptr, 1, len, fp)
128      *    will return a value equal to 'len'.  But the EOF will not be detected
129      *    until the next fread() which will return a value of 0.  Consequently,
130      *    realloc() will double the buffer before this final iteration of the
131      *    loop thereby guaranteeing (buflen > 0).  The if-guard here is just
132      *    for safety/paranoia.
133      */
134     assert (buflen > 0);
135     if (buflen > 0) {
136         bufmem[n] = '\0';
137     }
138     if (n > INT_MAX) {
139         log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum file size");
140     }
141     *buf = bufmem;
142     *len = (int) n;
143     return;
144 }
145 
146 
147 void
read_data_from_string(const char * s,void ** buf,int * len)148 read_data_from_string (const char *s, void **buf, int *len)
149 {
150     size_t  n;
151     char   *p;
152 
153     assert (buf != NULL);
154     assert (len != NULL);
155 
156     *buf = NULL;
157     *len = 0;
158 
159     if (s == NULL) {
160         return;
161     }
162     n = strlen (s);
163     if (n == 0) {
164         return;
165     }
166     p = malloc (n + 1);
167     if (p == NULL) {
168         log_errno (EMUNGE_NO_MEMORY, LOG_ERR,
169             "Failed to allocate %lu bytes", n + 1);
170     }
171     strncpy (p, s, n + 1);
172     p[n] = '\0';        /* null termination here is technically unnecessary */
173 
174     if (n > INT_MAX) {
175         log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum string size");
176     }
177     *buf = p;
178     *len = (int) n;
179     return;
180 }
181