• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015, Intel Corporation
3  * Copyright (C) 2015 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Written by William Roberts <william.c.roberts@intel.com>
18  *
19  */
20 
21 #define LOG_TAG "packagelistparser"
22 
23 #include <errno.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/limits.h>
29 
30 #include <log/log.h>
31 #include <packagelistparser/packagelistparser.h>
32 
33 #define CLOGE(fmt, ...) \
34     do {\
35         IF_ALOGE() {\
36             ALOGE(fmt, ##__VA_ARGS__);\
37         }\
38     } while(0)
39 
get_gid_cnt(const char * gids)40 static size_t get_gid_cnt(const char *gids)
41 {
42     size_t cnt;
43 
44     if (*gids == '\0') {
45         return 0;
46     }
47 
48     if (!strcmp(gids, "none")) {
49         return 0;
50     }
51 
52     for (cnt = 1; gids[cnt]; gids[cnt] == ',' ? cnt++ : *gids++)
53         ;
54 
55     return cnt;
56 }
57 
parse_gids(char * gids,gid_t * gid_list,size_t * cnt)58 static bool parse_gids(char *gids, gid_t *gid_list, size_t *cnt)
59 {
60     gid_t gid;
61     char* token;
62     char *endptr;
63     size_t cmp = 0;
64 
65     while ((token = strsep(&gids, ",\r\n"))) {
66 
67         if (cmp > *cnt) {
68             return false;
69         }
70 
71         gid = strtoul(token, &endptr, 10);
72         if (*endptr != '\0') {
73             return false;
74         }
75 
76         /*
77          * if unsigned long is greater than size of gid_t,
78          * prevent a truncation based roll-over
79          */
80         if (gid > GID_MAX) {
81             CLOGE("A gid in field \"gid list\" greater than GID_MAX");
82             return false;
83         }
84 
85         gid_list[cmp++] = gid;
86     }
87     return true;
88 }
89 
packagelist_parse(pfn_on_package callback,void * userdata)90 extern bool packagelist_parse(pfn_on_package callback, void *userdata)
91 {
92 
93     FILE *fp;
94     char *cur;
95     char *next;
96     char *endptr;
97     unsigned long tmp;
98     ssize_t bytesread;
99 
100     bool rc = false;
101     char *buf = NULL;
102     size_t buflen = 0;
103     unsigned long lineno = 1;
104     const char *errmsg = NULL;
105     struct pkg_info *pkg_info = NULL;
106 
107     fp = fopen(PACKAGES_LIST_FILE, "re");
108     if (!fp) {
109         CLOGE("Could not open: \"%s\", error: \"%s\"\n", PACKAGES_LIST_FILE,
110                 strerror(errno));
111         return false;
112     }
113 
114     while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
115 
116         pkg_info = calloc(1, sizeof(*pkg_info));
117         if (!pkg_info) {
118             goto err;
119         }
120 
121         next = buf;
122 
123         cur = strsep(&next, " \t\r\n");
124         if (!cur) {
125             errmsg = "Could not get next token for \"package name\"";
126             goto err;
127         }
128 
129         pkg_info->name = strdup(cur);
130         if (!pkg_info->name) {
131             goto err;
132         }
133 
134         cur = strsep(&next, " \t\r\n");
135         if (!cur) {
136             errmsg = "Could not get next token for field \"uid\"";
137             goto err;
138         }
139 
140         tmp = strtoul(cur, &endptr, 10);
141         if (*endptr != '\0') {
142             errmsg = "Could not convert field \"uid\" to integer value";
143             goto err;
144         }
145 
146         /*
147          * if unsigned long is greater than size of uid_t,
148          * prevent a truncation based roll-over
149          */
150         if (tmp > UID_MAX) {
151             errmsg = "Field \"uid\" greater than UID_MAX";
152             goto err;
153         }
154 
155         pkg_info->uid = (uid_t) tmp;
156 
157         cur = strsep(&next, " \t\r\n");
158         if (!cur) {
159             errmsg = "Could not get next token for field \"debuggable\"";
160             goto err;
161         }
162 
163         tmp = strtoul(cur, &endptr, 10);
164         if (*endptr != '\0') {
165             errmsg = "Could not convert field \"debuggable\" to integer value";
166             goto err;
167         }
168 
169         /* should be a valid boolean of 1 or 0 */
170         if (!(tmp == 0 || tmp == 1)) {
171             errmsg = "Field \"debuggable\" is not 0 or 1 boolean value";
172             goto err;
173         }
174 
175         pkg_info->debuggable = (bool) tmp;
176 
177         cur = strsep(&next, " \t\r\n");
178         if (!cur) {
179             errmsg = "Could not get next token for field \"data dir\"";
180             goto err;
181         }
182 
183         pkg_info->data_dir = strdup(cur);
184         if (!pkg_info->data_dir) {
185             goto err;
186         }
187 
188         cur = strsep(&next, " \t\r\n");
189         if (!cur) {
190             errmsg = "Could not get next token for field \"seinfo\"";
191             goto err;
192         }
193 
194         pkg_info->seinfo = strdup(cur);
195         if (!pkg_info->seinfo) {
196             goto err;
197         }
198 
199         cur = strsep(&next, " \t\r\n");
200         if (!cur) {
201             errmsg = "Could not get next token for field \"gid(s)\"";
202             goto err;
203         }
204 
205         /*
206          * Parse the gid list, could be in the form of none, single gid or list:
207          * none
208          * gid
209          * gid, gid ...
210          */
211         pkg_info->gids.cnt = get_gid_cnt(cur);
212         if (pkg_info->gids.cnt > 0) {
213 
214             pkg_info->gids.gids = calloc(pkg_info->gids.cnt, sizeof(gid_t));
215             if (!pkg_info->gids.gids) {
216                 goto err;
217             }
218 
219             rc = parse_gids(cur, pkg_info->gids.gids, &pkg_info->gids.cnt);
220             if (!rc) {
221                 errmsg = "Could not parse field \"gid list\"";
222                 goto err;
223             }
224         }
225 
226         cur = strsep(&next, " \t\r\n");
227         if (cur) {
228             tmp = strtoul(cur, &endptr, 10);
229             if (*endptr != '\0') {
230                 errmsg = "Could not convert field \"profileable_from_shell\" to integer value";
231                 goto err;
232             }
233 
234             /* should be a valid boolean of 1 or 0 */
235             if (!(tmp == 0 || tmp == 1)) {
236                 errmsg = "Field \"profileable_from_shell\" is not 0 or 1 boolean value";
237                 goto err;
238             }
239 
240             pkg_info->profileable_from_shell = (bool)tmp;
241         }
242         cur = strsep(&next, " \t\r\n");
243         if (cur) {
244             tmp = strtoul(cur, &endptr, 10);
245             if (*endptr != '\0') {
246                 errmsg = "Could not convert field \"versionCode\" to integer value";
247                 goto err;
248             }
249             pkg_info->version_code = tmp;
250         }
251 
252         rc = callback(pkg_info, userdata);
253         if (rc == false) {
254             /*
255              * We do not log this as this can be intentional from
256              * callback to abort processing. We go to out to not
257              * free the pkg_info
258              */
259             rc = true;
260             goto out;
261         }
262         lineno++;
263     }
264 
265     rc = true;
266 
267 out:
268     free(buf);
269     fclose(fp);
270     return rc;
271 
272 err:
273     if (errmsg) {
274         CLOGE("Error Parsing \"%s\" on line: %lu for reason: %s",
275                 PACKAGES_LIST_FILE, lineno, errmsg);
276     }
277     rc = false;
278     packagelist_free(pkg_info);
279     goto out;
280 }
281 
packagelist_free(pkg_info * info)282 void packagelist_free(pkg_info *info)
283 {
284     if (info) {
285         free(info->name);
286         free(info->data_dir);
287         free(info->seinfo);
288         free(info->gids.gids);
289         free(info);
290     }
291 }
292