Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2015 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <stdlib.h>
22 :
23 : #include "util/util.h"
24 : #include "util/strtonum.h"
25 : #include "tools/common/sss_colondb.h"
26 :
27 : #define IS_STD_FILE(db) ((db)->file == stdin || (db)->file == stdout)
28 :
29 0 : static char *read_field_as_string(char *line,
30 : const char **_value)
31 : {
32 : char *rest;
33 : char *value;
34 :
35 0 : if (line == NULL || *line == '\n' || *line == '\0') {
36 : /* There is nothing else to read. */
37 0 : rest = NULL;
38 0 : value = NULL;
39 0 : goto done;
40 : }
41 :
42 0 : if (*line == ':') {
43 : /* Special case for empty value. */
44 0 : *line = '\0';
45 0 : rest = line + 1;
46 0 : value = NULL;
47 0 : goto done;
48 : }
49 :
50 : /* Value starts at current position. */
51 0 : value = line;
52 :
53 : /* Find next field delimiter. */
54 0 : rest = strchr(line, ':');
55 0 : if (rest == NULL) {
56 : /* There is no more field. Remove \n from the end. */
57 0 : rest = strchr(line, '\n');
58 0 : if (rest != NULL) {
59 0 : *rest = '\0';
60 0 : rest = NULL;
61 : }
62 0 : goto done;
63 : }
64 :
65 : /* Remove it and step one character further. */
66 0 : *rest = '\0';
67 0 : rest++;
68 :
69 : done:
70 0 : *_value = value;
71 :
72 0 : return rest;
73 : }
74 :
75 0 : static char *read_field_as_uint32(char *line,
76 : uint32_t *_value)
77 : {
78 : const char *str;
79 : char *rest;
80 : errno_t ret;
81 :
82 0 : rest = read_field_as_string(line, &str);
83 0 : if (str == NULL) {
84 0 : *_value = 0;
85 0 : return rest;
86 : }
87 :
88 0 : *_value = strtouint32(str, NULL, 10);
89 0 : if (errno != 0) {
90 0 : ret = errno;
91 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse number [%d]: %s\n",
92 : ret, sss_strerror(ret));
93 :
94 0 : *_value = 0;
95 : }
96 :
97 0 : return rest;
98 : }
99 :
100 : struct sss_colondb {
101 : FILE *file;
102 : enum sss_colondb_mode mode;
103 : };
104 :
105 0 : errno_t sss_colondb_readline(TALLOC_CTX *mem_ctx,
106 : struct sss_colondb *db,
107 : struct sss_colondb_read_field *table)
108 : {
109 : int readchars;
110 0 : size_t linelen = 0;
111 0 : char *line = NULL;
112 : char *tcline;
113 : char *rest;
114 : errno_t ret;
115 : int i;
116 :
117 0 : if (db->mode != SSS_COLONDB_READ) {
118 0 : return ERR_INTERNAL;
119 : }
120 :
121 0 : readchars = getline(&line, &linelen, db->file);
122 0 : if (readchars == -1) {
123 : /* Nothing was read. */
124 0 : if (errno != 0) {
125 0 : ret = errno;
126 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read line [%d]: %s",
127 : ret, sss_strerror(ret));
128 0 : return ret;
129 : }
130 :
131 0 : return EOF;
132 : }
133 :
134 : /* Copy line to mem_ctx. */
135 0 : tcline = talloc_strdup(mem_ctx, line);
136 :
137 0 : free(line);
138 0 : line = NULL;
139 :
140 0 : if (tcline == NULL) {
141 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
142 0 : return ENOMEM;
143 : }
144 :
145 0 : rest = tcline;
146 0 : for (i = 0; table[i].type != SSS_COLONDB_SENTINEL; i++) {
147 0 : switch (table[i].type) {
148 : case SSS_COLONDB_UINT32:
149 0 : rest = read_field_as_uint32(rest, table[i].data.uint32);
150 0 : break;
151 : case SSS_COLONDB_STRING:
152 0 : rest = read_field_as_string(rest, table[i].data.str);
153 0 : break;
154 : case SSS_COLONDB_SENTINEL:
155 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Trying to process sentinel?!\n");
156 0 : ret = ERR_INTERNAL;
157 0 : goto done;
158 : }
159 :
160 0 : if (rest == NULL && table[i + 1].type != SSS_COLONDB_SENTINEL) {
161 0 : DEBUG(SSSDBG_CRIT_FAILURE,
162 : "Line contains less values than expected!\n");
163 0 : ret = EINVAL;
164 0 : goto done;
165 0 : } else if (rest != NULL && table[i + 1].type == SSS_COLONDB_SENTINEL) {
166 0 : DEBUG(SSSDBG_CRIT_FAILURE,
167 : "Line contains more values than expected!\n");
168 0 : ret = EINVAL;
169 0 : goto done;
170 : }
171 : }
172 :
173 0 : ret = EOK;
174 :
175 : done:
176 0 : if (ret != EOK) {
177 0 : talloc_free(tcline);
178 : }
179 :
180 0 : return ret;
181 : }
182 :
183 0 : errno_t sss_colondb_writeline(struct sss_colondb *db,
184 : struct sss_colondb_write_field *table)
185 : {
186 : TALLOC_CTX *tmp_ctx;
187 0 : char *line = NULL;
188 : errno_t ret;
189 : int i;
190 :
191 0 : if (db->mode != SSS_COLONDB_WRITE) {
192 0 : return ERR_INTERNAL;
193 : }
194 :
195 0 : tmp_ctx = talloc_new(NULL);
196 0 : if (tmp_ctx == NULL) {
197 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
198 0 : return ENOMEM;
199 : }
200 :
201 0 : for (i = 0; table[i].type != SSS_COLONDB_SENTINEL; i++) {
202 0 : switch (table[i].type) {
203 : case SSS_COLONDB_UINT32:
204 0 : if (table[i].data.uint32 == 0) {
205 0 : line = talloc_asprintf_append(line, ":");
206 : } else {
207 0 : line = talloc_asprintf_append(line, ":%u", table[i].data.uint32);
208 : }
209 0 : break;
210 : case SSS_COLONDB_STRING:
211 0 : if (table[i].data.str == NULL) {
212 0 : line = talloc_asprintf_append(line, ":");
213 : } else {
214 0 : line = talloc_asprintf_append(line, ":%s", table[i].data.str);
215 : }
216 0 : break;
217 : case SSS_COLONDB_SENTINEL:
218 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Trying to process sentinel?!\n");
219 0 : ret = ERR_INTERNAL;
220 0 : goto done;
221 : }
222 :
223 0 : if (line == NULL) {
224 0 : ret = ENOMEM;
225 0 : goto done;
226 : }
227 : }
228 :
229 : /* Remove starting : */
230 0 : line++;
231 :
232 0 : fprintf(db->file, "%s\n", line);
233 0 : fflush(db->file);
234 :
235 0 : ret = EOK;
236 :
237 : done:
238 0 : talloc_free(tmp_ctx);
239 :
240 0 : return ret;
241 : }
242 :
243 0 : static int sss_colondb_close(void *pvt)
244 : {
245 0 : struct sss_colondb *db = talloc_get_type(pvt, struct sss_colondb);
246 :
247 0 : if (db->file == NULL || IS_STD_FILE(db)) {
248 0 : return 0;
249 : }
250 :
251 0 : fclose(db->file);
252 0 : db->file = NULL;
253 :
254 0 : return 0;
255 : }
256 :
257 0 : static FILE *open_db(const char *filename, enum sss_colondb_mode mode)
258 : {
259 0 : FILE *fp = NULL;
260 : errno_t ret;
261 :
262 0 : errno = 0;
263 :
264 0 : switch (mode) {
265 : case SSS_COLONDB_READ:
266 0 : fp = filename == NULL ? stdin : fopen(filename, "r");
267 0 : break;
268 : case SSS_COLONDB_WRITE:
269 0 : fp = filename == NULL ? stdout : fopen(filename, "w");
270 0 : break;
271 : }
272 :
273 0 : if (fp == NULL && filename != NULL) {
274 0 : ret = errno;
275 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to open file %s [%d]: %s\n",
276 : filename, ret, sss_strerror(ret));
277 : }
278 :
279 0 : return fp;
280 : }
281 :
282 0 : struct sss_colondb *sss_colondb_open(TALLOC_CTX *mem_ctx,
283 : enum sss_colondb_mode mode,
284 : const char *filename)
285 : {
286 : struct sss_colondb *db;
287 :
288 0 : db = talloc_zero(mem_ctx, struct sss_colondb);
289 0 : if (db == NULL) {
290 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
291 0 : return NULL;
292 : }
293 :
294 0 : db->file = open_db(filename, mode);
295 0 : db->mode = mode;
296 :
297 0 : if (db->file == NULL) {
298 0 : talloc_free(db);
299 0 : return NULL;
300 : }
301 :
302 0 : talloc_set_destructor((TALLOC_CTX *)db, sss_colondb_close);
303 :
304 0 : return db;
305 : }
|