util.c revision a613819a96eeede9f9702d145e0575d459fdfd7a
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdarg.h>
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include <fcntl.h>
22#include <ctype.h>
23#include <errno.h>
24#include <time.h>
25#include <ftw.h>
26
27#include <selinux/label.h>
28
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/un.h>
33
34/* for ANDROID_SOCKET_* */
35#include <cutils/sockets.h>
36
37#include <private/android_filesystem_config.h>
38
39#include "init.h"
40#include "log.h"
41#include "util.h"
42
43/*
44 * android_name_to_id - returns the integer uid/gid associated with the given
45 * name, or -1U on error.
46 */
47static unsigned int android_name_to_id(const char *name)
48{
49    const struct android_id_info *info = android_ids;
50    unsigned int n;
51
52    for (n = 0; n < android_id_count; n++) {
53        if (!strcmp(info[n].name, name))
54            return info[n].aid;
55    }
56
57    return -1U;
58}
59
60/*
61 * decode_uid - decodes and returns the given string, which can be either the
62 * numeric or name representation, into the integer uid or gid. Returns -1U on
63 * error.
64 */
65unsigned int decode_uid(const char *s)
66{
67    unsigned int v;
68
69    if (!s || *s == '\0')
70        return -1U;
71    if (isalpha(s[0]))
72        return android_name_to_id(s);
73
74    errno = 0;
75    v = (unsigned int) strtoul(s, 0, 0);
76    if (errno)
77        return -1U;
78    return v;
79}
80
81/*
82 * create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR
83 * ("/dev/socket") as dictated in init.rc. This socket is inherited by the
84 * daemon. We communicate the file descriptor's value via the environment
85 * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
86 */
87int create_socket(const char *name, int type, mode_t perm, uid_t uid,
88                  gid_t gid, const char *socketcon)
89{
90    struct sockaddr_un addr;
91    int fd, ret;
92    char *filecon;
93
94    if (socketcon)
95        setsockcreatecon(socketcon);
96
97    fd = socket(PF_UNIX, type, 0);
98    if (fd < 0) {
99        ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
100        return -1;
101    }
102
103    if (socketcon)
104        setsockcreatecon(NULL);
105
106    memset(&addr, 0 , sizeof(addr));
107    addr.sun_family = AF_UNIX;
108    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
109             name);
110
111    ret = unlink(addr.sun_path);
112    if (ret != 0 && errno != ENOENT) {
113        ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
114        goto out_close;
115    }
116
117    filecon = NULL;
118    if (sehandle) {
119        ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
120        if (ret == 0)
121            setfscreatecon(filecon);
122    }
123
124    ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
125    if (ret) {
126        ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));
127        goto out_unlink;
128    }
129
130    setfscreatecon(NULL);
131    freecon(filecon);
132
133    chown(addr.sun_path, uid, gid);
134    chmod(addr.sun_path, perm);
135
136    INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
137         addr.sun_path, perm, uid, gid);
138
139    return fd;
140
141out_unlink:
142    unlink(addr.sun_path);
143out_close:
144    close(fd);
145    return -1;
146}
147
148/* reads a file, making sure it is terminated with \n \0 */
149void *read_file(const char *fn, unsigned *_sz)
150{
151    char *data;
152    int sz;
153    int fd;
154    struct stat sb;
155
156    data = 0;
157    fd = open(fn, O_RDONLY);
158    if(fd < 0) return 0;
159
160    // for security reasons, disallow world-writable
161    // or group-writable files
162    if (fstat(fd, &sb) < 0) {
163        ERROR("fstat failed for '%s'\n", fn);
164        goto oops;
165    }
166    if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
167        ERROR("skipping insecure file '%s'\n", fn);
168        goto oops;
169    }
170
171    sz = lseek(fd, 0, SEEK_END);
172    if(sz < 0) goto oops;
173
174    if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
175
176    data = (char*) malloc(sz + 2);
177    if(data == 0) goto oops;
178
179    if(read(fd, data, sz) != sz) goto oops;
180    close(fd);
181    data[sz] = '\n';
182    data[sz+1] = 0;
183    if(_sz) *_sz = sz;
184    return data;
185
186oops:
187    close(fd);
188    if(data != 0) free(data);
189    return 0;
190}
191
192#define MAX_MTD_PARTITIONS 16
193
194static struct {
195    char name[16];
196    int number;
197} mtd_part_map[MAX_MTD_PARTITIONS];
198
199static int mtd_part_count = -1;
200
201static void find_mtd_partitions(void)
202{
203    int fd;
204    char buf[1024];
205    char *pmtdbufp;
206    ssize_t pmtdsize;
207    int r;
208
209    fd = open("/proc/mtd", O_RDONLY);
210    if (fd < 0)
211        return;
212
213    buf[sizeof(buf) - 1] = '\0';
214    pmtdsize = read(fd, buf, sizeof(buf) - 1);
215    pmtdbufp = buf;
216    while (pmtdsize > 0) {
217        int mtdnum, mtdsize, mtderasesize;
218        char mtdname[16];
219        mtdname[0] = '\0';
220        mtdnum = -1;
221        r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
222                   &mtdnum, &mtdsize, &mtderasesize, mtdname);
223        if ((r == 4) && (mtdname[0] == '"')) {
224            char *x = strchr(mtdname + 1, '"');
225            if (x) {
226                *x = 0;
227            }
228            INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
229            if (mtd_part_count < MAX_MTD_PARTITIONS) {
230                strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
231                mtd_part_map[mtd_part_count].number = mtdnum;
232                mtd_part_count++;
233            } else {
234                ERROR("too many mtd partitions\n");
235            }
236        }
237        while (pmtdsize > 0 && *pmtdbufp != '\n') {
238            pmtdbufp++;
239            pmtdsize--;
240        }
241        if (pmtdsize > 0) {
242            pmtdbufp++;
243            pmtdsize--;
244        }
245    }
246    close(fd);
247}
248
249int mtd_name_to_number(const char *name)
250{
251    int n;
252    if (mtd_part_count < 0) {
253        mtd_part_count = 0;
254        find_mtd_partitions();
255    }
256    for (n = 0; n < mtd_part_count; n++) {
257        if (!strcmp(name, mtd_part_map[n].name)) {
258            return mtd_part_map[n].number;
259        }
260    }
261    return -1;
262}
263
264/*
265 * gettime() - returns the time in seconds of the system's monotonic clock or
266 * zero on error.
267 */
268time_t gettime(void)
269{
270    struct timespec ts;
271    int ret;
272
273    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
274    if (ret < 0) {
275        ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
276        return 0;
277    }
278
279    return ts.tv_sec;
280}
281
282int mkdir_recursive(const char *pathname, mode_t mode)
283{
284    char buf[128];
285    const char *slash;
286    const char *p = pathname;
287    int width;
288    int ret;
289    struct stat info;
290
291    while ((slash = strchr(p, '/')) != NULL) {
292        width = slash - pathname;
293        p = slash + 1;
294        if (width < 0)
295            break;
296        if (width == 0)
297            continue;
298        if ((unsigned int)width > sizeof(buf) - 1) {
299            ERROR("path too long for mkdir_recursive\n");
300            return -1;
301        }
302        memcpy(buf, pathname, width);
303        buf[width] = 0;
304        if (stat(buf, &info) != 0) {
305            ret = make_dir(buf, mode);
306            if (ret && errno != EEXIST)
307                return ret;
308        }
309    }
310    ret = make_dir(pathname, mode);
311    if (ret && errno != EEXIST)
312        return ret;
313    return 0;
314}
315
316/*
317 * replaces any unacceptable characters with '_', the
318 * length of the resulting string is equal to the input string
319 */
320void sanitize(char *s)
321{
322    const char* accept =
323            "abcdefghijklmnopqrstuvwxyz"
324            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
325            "0123456789"
326            "_-.";
327
328    if (!s)
329        return;
330
331    for (; *s; s++) {
332        s += strspn(s, accept);
333        if (*s) *s = '_';
334    }
335}
336
337void make_link(const char *oldpath, const char *newpath)
338{
339    int ret;
340    char buf[256];
341    char *slash;
342    int width;
343
344    slash = strrchr(newpath, '/');
345    if (!slash)
346        return;
347    width = slash - newpath;
348    if (width <= 0 || width > (int)sizeof(buf) - 1)
349        return;
350    memcpy(buf, newpath, width);
351    buf[width] = 0;
352    ret = mkdir_recursive(buf, 0755);
353    if (ret)
354        ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno);
355
356    ret = symlink(oldpath, newpath);
357    if (ret && errno != EEXIST)
358        ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno);
359}
360
361void remove_link(const char *oldpath, const char *newpath)
362{
363    char path[256];
364    ssize_t ret;
365    ret = readlink(newpath, path, sizeof(path) - 1);
366    if (ret <= 0)
367        return;
368    path[ret] = 0;
369    if (!strcmp(path, oldpath))
370        unlink(newpath);
371}
372
373int wait_for_file(const char *filename, int timeout)
374{
375    struct stat info;
376    time_t timeout_time = gettime() + timeout;
377    int ret = -1;
378
379    while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
380        usleep(10000);
381
382    return ret;
383}
384
385void open_devnull_stdio(void)
386{
387    int fd;
388    static const char *name = "/dev/__null__";
389    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
390        fd = open(name, O_RDWR);
391        unlink(name);
392        if (fd >= 0) {
393            dup2(fd, 0);
394            dup2(fd, 1);
395            dup2(fd, 2);
396            if (fd > 2) {
397                close(fd);
398            }
399            return;
400        }
401    }
402
403    exit(1);
404}
405
406void get_hardware_name(char *hardware, unsigned int *revision)
407{
408    const char *cpuinfo = "/proc/cpuinfo";
409    char *data = NULL;
410    size_t len = 0, limit = 1024;
411    int fd, n;
412    char *x, *hw, *rev;
413
414    /* Hardware string was provided on kernel command line */
415    if (hardware[0])
416        return;
417
418    fd = open(cpuinfo, O_RDONLY);
419    if (fd < 0) return;
420
421    for (;;) {
422        x = realloc(data, limit);
423        if (!x) {
424            ERROR("Failed to allocate memory to read %s\n", cpuinfo);
425            goto done;
426        }
427        data = x;
428
429        n = read(fd, data + len, limit - len);
430        if (n < 0) {
431            ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno);
432            goto done;
433        }
434        len += n;
435
436        if (len < limit)
437            break;
438
439        /* We filled the buffer, so increase size and loop to read more */
440        limit *= 2;
441    }
442
443    data[len] = 0;
444    hw = strstr(data, "\nHardware");
445    rev = strstr(data, "\nRevision");
446
447    if (hw) {
448        x = strstr(hw, ": ");
449        if (x) {
450            x += 2;
451            n = 0;
452            while (*x && *x != '\n') {
453                if (!isspace(*x))
454                    hardware[n++] = tolower(*x);
455                x++;
456                if (n == 31) break;
457            }
458            hardware[n] = 0;
459        }
460    }
461
462    if (rev) {
463        x = strstr(rev, ": ");
464        if (x) {
465            *revision = strtoul(x + 2, 0, 16);
466        }
467    }
468
469done:
470    close(fd);
471    free(data);
472}
473
474void import_kernel_cmdline(int in_qemu,
475                           void (*import_kernel_nv)(char *name, int in_qemu))
476{
477    char cmdline[2048];
478    char *ptr;
479    int fd;
480
481    fd = open("/proc/cmdline", O_RDONLY);
482    if (fd >= 0) {
483        int n = read(fd, cmdline, sizeof(cmdline) - 1);
484        if (n < 0) n = 0;
485
486        /* get rid of trailing newline, it happens */
487        if (n > 0 && cmdline[n-1] == '\n') n--;
488
489        cmdline[n] = 0;
490        close(fd);
491    } else {
492        cmdline[0] = 0;
493    }
494
495    ptr = cmdline;
496    while (ptr && *ptr) {
497        char *x = strchr(ptr, ' ');
498        if (x != 0) *x++ = 0;
499        import_kernel_nv(ptr, in_qemu);
500        ptr = x;
501    }
502}
503
504int make_dir(const char *path, mode_t mode)
505{
506    int rc;
507
508    char *secontext = NULL;
509
510    if (sehandle) {
511        selabel_lookup(sehandle, &secontext, path, mode);
512        setfscreatecon(secontext);
513    }
514
515    rc = mkdir(path, mode);
516
517    if (secontext) {
518        int save_errno = errno;
519        freecon(secontext);
520        setfscreatecon(NULL);
521        errno = save_errno;
522    }
523
524    return rc;
525}
526
527static int restorecon_sb(const char *pathname, const struct stat *sb)
528{
529    char *secontext = NULL;
530    char *oldsecontext = NULL;
531    int i;
532
533    if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0)
534        return -errno;
535
536    if (lgetfilecon(pathname, &oldsecontext) < 0) {
537        freecon(secontext);
538        return -errno;
539    }
540
541    if (strcmp(oldsecontext, secontext) != 0) {
542        if (lsetfilecon(pathname, secontext) < 0) {
543            freecon(oldsecontext);
544            freecon(secontext);
545            return -errno;
546        }
547    }
548    freecon(oldsecontext);
549    freecon(secontext);
550    return 0;
551}
552
553int restorecon(const char *pathname)
554{
555    struct stat sb;
556
557    if (is_selinux_enabled() <= 0 || !sehandle)
558        return 0;
559
560    if (lstat(pathname, &sb) < 0)
561        return -errno;
562
563    return restorecon_sb(pathname, &sb);
564}
565
566static int nftw_restorecon(const char* filename, const struct stat* statptr,
567    int fileflags __attribute__((unused)),
568    struct FTW* pftw __attribute__((unused)))
569{
570    restorecon_sb(filename, statptr);
571    return 0;
572}
573
574int restorecon_recursive(const char* pathname)
575{
576    int fd_limit = 20;
577    int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
578
579    if (is_selinux_enabled() <= 0 || !sehandle)
580        return 0;
581
582    return nftw(pathname, nftw_restorecon, fd_limit, flags);
583}
584