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 4 : static char *read_field_as_string(char *line,
30 : const char **_value)
31 : {
32 : char *rest;
33 : char *value;
34 :
35 4 : 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 4 : 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 4 : value = line;
52 :
53 : /* Find next field delimiter. */
54 4 : rest = strchr(line, ':');
55 4 : if (rest == NULL) {
56 : /* There is no more field. Remove \n from the end. */
57 2 : rest = strchr(line, '\n');
58 2 : if (rest != NULL) {
59 2 : *rest = '\0';
60 2 : rest = NULL;
61 : }
62 2 : goto done;
63 : }
64 :
65 : /* Remove it and step one character further. */
66 2 : *rest = '\0';
67 2 : rest++;
68 :
69 : done:
70 4 : *_value = value;
71 :
72 4 : return rest;
73 : }
74 :
75 2 : 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 2 : rest = read_field_as_string(line, &str);
83 2 : if (str == NULL) {
84 0 : *_value = 0;
85 0 : return rest;
86 : }
87 :
88 2 : *_value = strtouint32(str, NULL, 10);
89 2 : 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 2 : return rest;
98 : }
99 :
100 : struct sss_colondb {
101 : FILE *file;
102 : enum sss_colondb_mode mode;
103 : };
104 :
105 3 : 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 3 : size_t linelen = 0;
111 3 : char *line = NULL;
112 : char *tcline;
113 : char *rest;
114 : errno_t ret;
115 : int i;
116 :
117 3 : if (db->mode != SSS_COLONDB_READ) {
118 0 : return ERR_INTERNAL;
119 : }
120 :
121 3 : readchars = getline(&line, &linelen, db->file);
122 3 : if (readchars == -1) {
123 : /* Nothing was read. */
124 :
125 1 : free(line);
126 1 : line = NULL;
127 :
128 1 : if (errno != 0) {
129 0 : ret = errno;
130 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to read line [%d]: %s\n",
131 : ret, sss_strerror(ret));
132 0 : return ret;
133 : }
134 :
135 1 : return EOF;
136 : }
137 :
138 : /* Copy line to mem_ctx. */
139 2 : tcline = talloc_strdup(mem_ctx, line);
140 :
141 2 : free(line);
142 2 : line = NULL;
143 :
144 2 : if (tcline == NULL) {
145 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strdup() failed\n");
146 0 : return ENOMEM;
147 : }
148 :
149 2 : rest = tcline;
150 6 : for (i = 0; table[i].type != SSS_COLONDB_SENTINEL; i++) {
151 4 : switch (table[i].type) {
152 : case SSS_COLONDB_UINT32:
153 2 : rest = read_field_as_uint32(rest, table[i].data.uint32);
154 2 : break;
155 : case SSS_COLONDB_STRING:
156 2 : rest = read_field_as_string(rest, table[i].data.str);
157 2 : break;
158 : case SSS_COLONDB_SENTINEL:
159 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Trying to process sentinel?!\n");
160 0 : ret = ERR_INTERNAL;
161 0 : goto done;
162 : }
163 :
164 4 : if (rest == NULL && table[i + 1].type != SSS_COLONDB_SENTINEL) {
165 0 : DEBUG(SSSDBG_CRIT_FAILURE,
166 : "Line contains less values than expected!\n");
167 0 : ret = EINVAL;
168 0 : goto done;
169 4 : } else if (rest != NULL && table[i + 1].type == SSS_COLONDB_SENTINEL) {
170 0 : DEBUG(SSSDBG_CRIT_FAILURE,
171 : "Line contains more values than expected!\n");
172 0 : ret = EINVAL;
173 0 : goto done;
174 : }
175 : }
176 :
177 2 : ret = EOK;
178 :
179 : done:
180 2 : if (ret != EOK) {
181 0 : talloc_free(tcline);
182 : }
183 :
184 2 : return ret;
185 : }
186 :
187 7 : errno_t sss_colondb_writeline(struct sss_colondb *db,
188 : struct sss_colondb_write_field *table)
189 : {
190 : TALLOC_CTX *tmp_ctx;
191 7 : char *line = NULL;
192 : errno_t ret;
193 : int i;
194 :
195 7 : if (db->mode != SSS_COLONDB_WRITE) {
196 0 : return ERR_INTERNAL;
197 : }
198 :
199 7 : tmp_ctx = talloc_new(NULL);
200 7 : if (tmp_ctx == NULL) {
201 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
202 0 : return ENOMEM;
203 : }
204 :
205 7 : line = talloc_strdup(tmp_ctx, "");
206 7 : if (line == NULL) {
207 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed.\n");
208 0 : ret = ENOMEM;
209 0 : goto done;
210 : }
211 :
212 21 : for (i = 0; table[i].type != SSS_COLONDB_SENTINEL; i++) {
213 14 : switch (table[i].type) {
214 : case SSS_COLONDB_UINT32:
215 7 : if (table[i].data.uint32 == 0) {
216 0 : line = talloc_asprintf_append(line, ":");
217 : } else {
218 7 : line = talloc_asprintf_append(line, ":%u", table[i].data.uint32);
219 : }
220 7 : break;
221 : case SSS_COLONDB_STRING:
222 7 : if (table[i].data.str == NULL) {
223 0 : line = talloc_asprintf_append(line, ":");
224 : } else {
225 7 : line = talloc_asprintf_append(line, ":%s", table[i].data.str);
226 : }
227 7 : break;
228 : case SSS_COLONDB_SENTINEL:
229 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Trying to process sentinel?!\n");
230 0 : ret = ERR_INTERNAL;
231 0 : goto done;
232 : }
233 :
234 14 : if (line == NULL) {
235 0 : ret = ENOMEM;
236 0 : goto done;
237 : }
238 : }
239 :
240 : /* Remove starting : */
241 7 : line++;
242 :
243 7 : fprintf(db->file, "%s\n", line);
244 7 : fflush(db->file);
245 :
246 7 : ret = EOK;
247 :
248 : done:
249 7 : talloc_free(tmp_ctx);
250 :
251 7 : return ret;
252 : }
253 :
254 14 : static int sss_colondb_close(void *pvt)
255 : {
256 14 : struct sss_colondb *db = talloc_get_type(pvt, struct sss_colondb);
257 :
258 14 : if (db->file == NULL || IS_STD_FILE(db)) {
259 0 : return 0;
260 : }
261 :
262 14 : fclose(db->file);
263 14 : db->file = NULL;
264 :
265 14 : return 0;
266 : }
267 :
268 16 : static FILE *open_db(const char *filename, enum sss_colondb_mode mode)
269 : {
270 16 : FILE *fp = NULL;
271 : errno_t ret;
272 :
273 16 : errno = 0;
274 :
275 16 : switch (mode) {
276 : case SSS_COLONDB_READ:
277 6 : fp = filename == NULL ? stdin : fopen(filename, "r");
278 6 : break;
279 : case SSS_COLONDB_WRITE:
280 10 : fp = filename == NULL ? stdout : fopen(filename, "w");
281 10 : break;
282 : }
283 :
284 16 : if (fp == NULL && filename != NULL) {
285 2 : ret = errno;
286 2 : DEBUG(SSSDBG_CRIT_FAILURE, "Unable to open file %s [%d]: %s\n",
287 : filename, ret, sss_strerror(ret));
288 : }
289 :
290 16 : return fp;
291 : }
292 :
293 16 : struct sss_colondb *sss_colondb_open(TALLOC_CTX *mem_ctx,
294 : enum sss_colondb_mode mode,
295 : const char *filename)
296 : {
297 : struct sss_colondb *db;
298 :
299 16 : db = talloc_zero(mem_ctx, struct sss_colondb);
300 16 : if (db == NULL) {
301 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
302 0 : return NULL;
303 : }
304 :
305 16 : db->file = open_db(filename, mode);
306 16 : db->mode = mode;
307 :
308 16 : if (db->file == NULL) {
309 2 : talloc_free(db);
310 2 : return NULL;
311 : }
312 :
313 14 : talloc_set_destructor((TALLOC_CTX *)db, sss_colondb_close);
314 :
315 14 : return db;
316 : }
|