Annotation of embedaddon/sudo/common/sudo_dso.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 2010, 2012-2014 Todd C. Miller <Todd.Miller@courtesan.com>
                      3:  *
                      4:  * Permission to use, copy, modify, and distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
                      7:  *
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16: 
                     17: #include <config.h>
                     18: 
                     19: #include <sys/types.h>
                     20: 
                     21: #include <stdio.h>
                     22: #ifdef STDC_HEADERS
                     23: # include <stdlib.h>
                     24: # include <stddef.h>
                     25: #else
                     26: # ifdef HAVE_STDLIB_H
                     27: #  include <stdlib.h>
                     28: # endif
                     29: #endif /* STDC_HEADERS */
                     30: #ifdef HAVE_STRING_H
                     31: # include <string.h>
                     32: #endif /* HAVE_STRING_H */
                     33: #ifdef HAVE_STRINGS_H
                     34: # include <strings.h>
                     35: #endif /* HAVE_STRINGS_H */
                     36: #if defined(HAVE_SHL_LOAD)
                     37: # include <dl.h>
                     38: #elif defined(HAVE_DLOPEN)
                     39: # include <dlfcn.h>
                     40: #endif
                     41: #include <errno.h>
                     42: 
                     43: #include "sudo_dso.h"
                     44: #include "missing.h"
                     45: 
                     46: /*
                     47:  * Pointer for statically compiled symbols.
                     48:  */
                     49: static struct sudo_preload_table *preload_table;
                     50: 
                     51: void
                     52: sudo_dso_preload_table(struct sudo_preload_table *table)
                     53: {
                     54:     preload_table = table;
                     55: }
                     56: 
                     57: #if defined(HAVE_SHL_LOAD)
                     58: 
                     59: # ifndef DYNAMIC_PATH
                     60: #  define DYNAMIC_PATH 0
                     61: # endif
                     62: 
                     63: void *
                     64: sudo_dso_load(const char *path, int mode)
                     65: {
                     66:     struct sudo_preload_table *pt;
                     67:     int flags = DYNAMIC_PATH | BIND_VERBOSE;
                     68: 
                     69:     if (mode == 0)
                     70:        mode = SUDO_DSO_LAZY;   /* default behavior */
                     71: 
                     72:     /* Check prelinked symbols first. */
                     73:     if (preload_table != NULL) {
                     74:        for (pt = preload_table; pt->handle != NULL; pt++) {
                     75:            if (pt->path != NULL && strcmp(path, pt->path) == 0)
                     76:                return pt->handle;
                     77:        }
                     78:     }
                     79: 
                     80:     /* We don't support SUDO_DSO_GLOBAL or SUDO_DSO_LOCAL yet. */
                     81:     if (ISSET(mode, SUDO_DSO_LAZY))
                     82:        flags |= BIND_DEFERRED;
                     83:     if (ISSET(mode, SUDO_DSO_NOW))
                     84:        flags |= BIND_IMMEDIATE;
                     85: 
                     86:     return (void *)shl_load(path, flags, 0L);
                     87: }
                     88: 
                     89: int
                     90: sudo_dso_unload(void *handle)
                     91: {
                     92:     struct sudo_preload_table *pt;
                     93: 
                     94:     /* Check prelinked symbols first. */
                     95:     if (preload_table != NULL) {
                     96:        for (pt = preload_table; pt->handle != NULL; pt++) {
                     97:            if (pt->handle == handle)
                     98:                return 0;
                     99:        }
                    100:     }
                    101: 
                    102:     return shl_unload((shl_t)handle);
                    103: }
                    104: 
                    105: void *
                    106: sudo_dso_findsym(void *vhandle, const char *symbol)
                    107: {
                    108:     struct sudo_preload_table *pt;
                    109:     shl_t handle = vhandle;
                    110:     void *value = NULL;
                    111: 
                    112:     /* Check prelinked symbols first. */
                    113:     if (preload_table != NULL) {
                    114:        for (pt = preload_table; pt->handle != NULL; pt++) {
                    115:            if (pt->handle == handle) {
                    116:                struct sudo_preload_symbol *sym;
                    117:                for (sym = pt->symbols; sym->name != NULL; sym++) {
                    118:                    if (strcmp(sym->name, symbol) == 0)
                    119:                        return sym->addr;
                    120:                }
                    121:                errno = ENOENT;
                    122:                return NULL;
                    123:            }
                    124:        }
                    125:     }
                    126: 
                    127:     /*
                    128:      * Note that the behavior of of SUDO_DSO_NEXT and SUDO_DSO_SELF 
                    129:      * differs from most implementations when called from
                    130:      * a shared library.
                    131:      */
                    132:     if (vhandle == SUDO_DSO_NEXT) {
                    133:        /* Iterate over all shared libs looking for symbol. */
                    134:        shl_t myhandle = PROG_HANDLE;
                    135:        struct shl_descriptor *desc;
                    136:        int idx = 0;
                    137: 
                    138:        /* Find program's real handle. */
                    139:        if (shl_gethandle(PROG_HANDLE, &desc) == 0)
                    140:            myhandle = desc->handle;
                    141:        while (shl_get(idx++, &desc) == 0) {
                    142:            if (desc->handle == myhandle)
                    143:                continue;
                    144:            if (shl_findsym(&desc->handle, symbol, TYPE_UNDEFINED, &value) == 0)
                    145:                break;
                    146:        }
                    147:     } else {
                    148:        if (vhandle == SUDO_DSO_DEFAULT)
                    149:            handle = NULL;
                    150:        else if (vhandle == SUDO_DSO_SELF)
                    151:            handle = PROG_HANDLE;
                    152:        (void)shl_findsym(&handle, symbol, TYPE_UNDEFINED, &value);
                    153:     }
                    154: 
                    155:     return value;
                    156: }
                    157: 
                    158: char *
                    159: sudo_dso_strerror(void)
                    160: {
                    161:     return strerror(errno);
                    162: }
                    163: 
                    164: #elif defined(HAVE_DLOPEN)
                    165: 
                    166: # ifndef RTLD_GLOBAL
                    167: #  define RTLD_GLOBAL  0
                    168: # endif
                    169: 
                    170: void *
                    171: sudo_dso_load(const char *path, int mode)
                    172: {
                    173:     struct sudo_preload_table *pt;
                    174:     int flags = 0;
                    175: 
                    176:     /* Check prelinked symbols first. */
                    177:     if (preload_table != NULL) {
                    178:        for (pt = preload_table; pt->handle != NULL; pt++) {
                    179:            if (pt->path != NULL && strcmp(path, pt->path) == 0)
                    180:                return pt->handle;
                    181:        }
                    182:     }
                    183: 
                    184:     /* Map SUDO_DSO_* -> RTLD_* */
                    185:     if (ISSET(mode, SUDO_DSO_LAZY))
                    186:        flags |= RTLD_LAZY;
                    187:     if (ISSET(mode, SUDO_DSO_NOW))
                    188:        flags |= RTLD_NOW;
                    189:     if (ISSET(mode, SUDO_DSO_GLOBAL))
                    190:        flags |= RTLD_GLOBAL;
                    191:     if (ISSET(mode, SUDO_DSO_LOCAL))
                    192:        flags |= RTLD_LOCAL;
                    193: 
                    194:     return dlopen(path, flags);
                    195: }
                    196: 
                    197: int
                    198: sudo_dso_unload(void *handle)
                    199: {
                    200:     struct sudo_preload_table *pt;
                    201: 
                    202:     /* Check prelinked symbols first. */
                    203:     if (preload_table != NULL) {
                    204:        for (pt = preload_table; pt->handle != NULL; pt++) {
                    205:            if (pt->handle == handle)
                    206:                return 0;
                    207:        }
                    208:     }
                    209: 
                    210:     return dlclose(handle);
                    211: }
                    212: 
                    213: void *
                    214: sudo_dso_findsym(void *handle, const char *symbol)
                    215: {
                    216:     struct sudo_preload_table *pt;
                    217: 
                    218:     /* Check prelinked symbols first. */
                    219:     if (preload_table != NULL) {
                    220:        for (pt = preload_table; pt->handle != NULL; pt++) {
                    221:            if (pt->handle == handle) {
                    222:                struct sudo_preload_symbol *sym;
                    223:                for (sym = pt->symbols; sym->name != NULL; sym++) {
                    224:                    if (strcmp(sym->name, symbol) == 0)
                    225:                        return sym->addr;
                    226:                }
                    227:                errno = ENOENT;
                    228:                return NULL;
                    229:            }
                    230:        }
                    231:     }
                    232: 
                    233:     /*
                    234:      * Not all implementations support the special handles.
                    235:      */
                    236:     if (handle == SUDO_DSO_NEXT) {
                    237: # ifdef RTLD_NEXT
                    238:        handle = RTLD_NEXT;
                    239: # else
                    240:        errno = ENOENT;
                    241:        return NULL;
                    242: # endif
                    243:     } else if (handle == SUDO_DSO_DEFAULT) {
                    244: # ifdef RTLD_DEFAULT
                    245:        handle = RTLD_DEFAULT;
                    246: # else
                    247:        errno = ENOENT;
                    248:        return NULL;
                    249: # endif
                    250:     } else if (handle == SUDO_DSO_SELF) {
                    251: # ifdef RTLD_SELF
                    252:        handle = RTLD_SELF;
                    253: # else
                    254:        errno = ENOENT;
                    255:        return NULL;
                    256: # endif
                    257:     }
                    258: 
                    259:     return dlsym(handle, symbol);
                    260: }
                    261: 
                    262: char *
                    263: sudo_dso_strerror(void)
                    264: {
                    265:     return dlerror();
                    266: }
                    267: 
                    268: #else /* !HAVE_SHL_LOAD && !HAVE_DLOPEN */
                    269: 
                    270: /*
                    271:  * Emulate dlopen() using a static list of symbols compiled into sudo.
                    272:  */
                    273: void *
                    274: sudo_dso_load(const char *path, int mode)
                    275: {
                    276:     struct sudo_preload_table *pt;
                    277: 
                    278:     /* Check prelinked symbols first. */
                    279:     if (preload_table != NULL) {
                    280:        for (pt = preload_table; pt->handle != NULL; pt++) {
                    281:            if (pt->path != NULL && strcmp(path, pt->path) == 0)
                    282:                return pt->handle;
                    283:        }
                    284:     }
                    285:     return NULL;
                    286: }
                    287: 
                    288: int
                    289: sudo_dso_unload(void *handle)
                    290: {
                    291:     struct sudo_preload_table *pt;
                    292: 
                    293:     if (preload_table != NULL) {
                    294:        for (pt = preload_table; pt->handle != NULL; pt++) {
                    295:            if (pt->handle == handle)
                    296:                return 0;
                    297:        }
                    298:     }
                    299:     return -1;
                    300: }
                    301: 
                    302: void *
                    303: sudo_dso_findsym(void *handle, const char *symbol)
                    304: {
                    305:     struct sudo_preload_table *pt;
                    306: 
                    307:     if (preload_table != NULL) {
                    308:        for (pt = preload_table; pt->handle != NULL; pt++) {
                    309:            if (pt->handle == handle) {
                    310:                struct sudo_preload_symbol *sym;
                    311:                for (sym = pt->symbols; sym->name != NULL; sym++) {
                    312:                    if (strcmp(sym->name, symbol) == 0)
                    313:                        return sym->addr;
                    314:                }
                    315:            }
                    316:        }
                    317:     }
                    318:     errno = ENOENT;
                    319:     return NULL;
                    320: }
                    321: 
                    322: char *
                    323: sudo_dso_strerror(void)
                    324: {
                    325:     return strerror(errno);
                    326: }
                    327: #endif /* !HAVE_SHL_LOAD && !HAVE_DLOPEN */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>