Check out CCAN ciniparser. Its a fork of the original iniparser (which is no longer maintained) and makes parsing INI style configuration files easy.
Code from the example (almost mirrored by the unit tests):
#include <stdio.h>
#include <stdbool.h>
#include <ccan/ciniparser/ciniparser.h>
#define CONFIG_FILE "/etc/config.ini"
int main(int argc, char *argv[])
{
        dictionary *d;
        char *val1;
        bool val2;
        double val3;
        int val4;
        d = ciniparser_load(CONFIG_FILE);
        if (d == NULL)
            return 1;
        val1 = ciniparser_getstring(d, "daemon:pidfile", NULL);
        val2 = ciniparser_getboolean(d, "daemon:debug", false);
        val3 = ciniparser_getdouble(d, "daemon:maxload", 3.5);
        val4 = ciniparser_getint(d, "daemon:maxchild", 5);
        ciniparser_freedict(d);
        return 0;
}
Of course, you can just drop the few files needed in your tree and #include "iniparser.h", there are no dependencies on other CCAN modules unless you want to run the unit tests.
A sample configuration might look like this:
[stooges]
larry=larry_stooge
curly=curly_stooge
moe=moe_stooge
shemp=questionable
[cartoons]
tom_hates=jerry
Getting the value of stooges:shemp would yield a statically allocated questionable that you would use as-is (without modifying) or allocate and duplicate (i.e. strdup()). It doesn't get much easier than that. Wrap access to the dictionary with a simple mutex and its thread safe.
CCAN is the Comprehensive C Archive network. Think CPAN , just C. Its a project Rusty Russell began a while ago which is finally gaining some traction.
Disclaimer: I maintain the module.