X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=libatalk%2Futil%2Fnetatalk_conf.c;h=bbbb3c3b8321f131d7d5e14d93bb4926fa819bc7;hp=8b060e5f6949573e14e18e337535340dff1f5d52;hb=4e7c44b51d025b4a068eeec8a5fc9f80e2f20f9e;hpb=949ba93384843d13099dd467aefc61e3b7185997 diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index 8b060e5f..bbbb3c3b 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -51,6 +51,7 @@ #include #include #include +#include #define VOLPASSLEN 8 #ifndef UUID_PRINTABLE_STRING_LENGTH @@ -401,8 +402,11 @@ static char *volxlate(const AFPObj *obj, /*! * check access list * - * this function wants something of the following form: - * "@group,name,name2,@group2,name3" or "@group name name2 @group2 name3" + * this function wants a string consisting of names seperated by comma + * or space. Names may be quoted within a pair of quotes. Groups are + * denoted by a leading @ symbol. + * Example: + * user1 user2, user3, @group1 @group2, @group3 "user name1", "@group name1" * A NULL argument allows everybody to have access. * We return three things: * -1: no list @@ -411,26 +415,31 @@ static char *volxlate(const AFPObj *obj, */ static int accessvol(const AFPObj *obj, const char *args, const char *name) { - char buf[MAXPATHLEN + 1], *p; + EC_INIT; + char *names = NULL, *p; struct group *gr; if (!args) - return -1; + EC_EXIT_STATUS(-1); - strlcpy(buf, args, sizeof(buf)); - if ((p = strtok(buf, ", ")) == NULL) /* nothing, return okay */ - return -1; + EC_NULL_LOG( names = strdup(args) ); + + if ((p = strtok_quote(names, ", ")) == NULL) /* nothing, return okay */ + EC_EXIT_STATUS(-1); while (p) { if (*p == '@') { /* it's a group */ if ((gr = getgrnam(p + 1)) && gmem(gr->gr_gid, obj->ngroups, obj->groups)) - return 1; + EC_EXIT_STATUS(1); } else if (strcasecmp(p, name) == 0) /* it's a user name */ - return 1; - p = strtok(NULL, ", "); + EC_EXIT_STATUS(1); + p = strtok_quote(NULL, ", "); } - return 0; +EC_CLEANUP: + if (names) + free(names); + EC_EXIT; } static int hostaccessvol(const AFPObj *obj, const char *volname, const char *args) @@ -505,13 +514,11 @@ static int hostaccessvol(const AFPObj *obj, const char *volname, const char *arg */ static const char *getoption(const dictionary *conf, const char *vol, const char *opt, const char *defsec, const char *defval) { - EC_INIT; const char *result; if ((!(result = iniparser_getstring(conf, vol, opt, NULL))) && (defsec != NULL)) result = iniparser_getstring(conf, defsec, opt, NULL); -EC_CLEANUP: if (result == NULL) result = defval; return result; @@ -530,13 +537,11 @@ EC_CLEANUP: */ static int getoption_bool(const dictionary *conf, const char *vol, const char *opt, const char *defsec, int defval) { - EC_INIT; int result; if (((result = iniparser_getboolean(conf, vol, opt, -1)) == -1) && (defsec != NULL)) result = iniparser_getboolean(conf, defsec, opt, -1); -EC_CLEANUP: if (result == -1) result = defval; return result; @@ -562,7 +567,6 @@ static struct vol *creatvol(AFPObj *obj, { EC_INIT; struct vol *volume = NULL; - size_t current_pathlen, another_pathlen; int i, suffixlen, vlen, tmpvlen, u8mvlen, macvlen; char tmpname[AFPVOL_U8MNAMELEN+1]; char path[MAXPATHLEN + 1]; @@ -571,9 +575,6 @@ static struct vol *creatvol(AFPObj *obj, uint16_t flags; const char *val; char *p, *q; - bool new_vol_nested = false; /* flag whether the new volume path is a subdirectory - * of an existing directory in which case we force - * "last" cnidsheme and read only behaviour */ strlcpy(path, path_in, MAXPATHLEN); @@ -590,46 +591,26 @@ static struct vol *creatvol(AFPObj *obj, /* Once volumes are loaded, we never change options again, we just delete em when they're removed from afp.conf */ - /* - * Check for duplicated or nested volumes, eg: - * /Volumes/name /Volumes/name [duplicate], and - * /Volumes/name /Volumes/name/dir [nested], but beware of simple strncmp test: - * /Volumes/name /Volumes/name1 [strncmp match if n=strlen("Volumes/name") -> false positive] - */ - current_pathlen = strlen(path); for (struct vol *vol = Volumes; vol; vol = vol->v_next) { - another_pathlen = strlen(vol->v_path); - if (strncmp(path, vol->v_path, MIN(current_pathlen, another_pathlen)) == 0) { - if (current_pathlen == another_pathlen) { - LOG(log_error, logtype_afpd, "volume \"%s\" paths is duplicated: \"%s\"", name, path); - vol->v_deleted = 0; - volume = vol; - goto EC_CLEANUP; - } else { - const char *shorter_path, *longer_path; - int shorter_len; - if (another_pathlen > current_pathlen) { - shorter_len = current_pathlen; - shorter_path = path; - longer_path = vol->v_path; - } else { - new_vol_nested = true; - shorter_len = another_pathlen; - shorter_path = vol->v_path; - longer_path = path; - } - if (longer_path[shorter_len] == '/') { - if (!new_vol_nested && STRCMP(vol->v_cnidscheme, !=, "last")) { - /* the volume "vol" is nested, we must force cnidscheme "last" and read-only */ - LOG(log_warning, logtype_afpd, "volume \"%s\" path \"%s\" is nested, set to read-only", - vol->v_configname, vol->v_path); - vol->v_flags = AFPVOL_RO; - free(vol->v_cnidscheme); - vol->v_cnidscheme = strdup("last"); - } - } - } + if (STRCMP(name, ==, vol->v_localname) && vol->v_deleted) { + /* + * reloading config, volume still present, nothing else to do, + * we don't change options for volumes once they're loaded + */ + vol->v_deleted = 0; + volume = vol; + EC_EXIT_STATUS(0); + } + if (STRCMP(path, ==, vol->v_path)) { + LOG(log_note, logtype_afpd, "volume \"%s\" path \"%s\" is the same as volumes \"%s\" path", + name, path, vol->v_configname); + EC_EXIT_STATUS(0); } + /* + * We could check for nested volume paths here, but + * nobody was able to come up with an implementation yet, + * that is simple, fast and correct. + */ } /* @@ -655,14 +636,14 @@ static struct vol *creatvol(AFPObj *obj, volume->v_vfs_ea = AFPVOL_EA_AUTO; volume->v_umask = obj->options.umask; - if (val = getoption(obj->iniconfig, section, "password", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "password", preset, NULL))) EC_NULL( volume->v_password = strdup(val) ); - if (val = getoption(obj->iniconfig, section, "veto files", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "veto files", preset, NULL))) EC_NULL( volume->v_veto = strdup(val) ); /* vol charset is in [G] and [V] */ - if (val = getoption(obj->iniconfig, section, "vol charset", preset, NULL)) { + if ((val = getoption(obj->iniconfig, section, "vol charset", preset, NULL))) { if (strcasecmp(val, "UTF-8") == 0) { val = strdup("UTF8"); } @@ -672,7 +653,7 @@ static struct vol *creatvol(AFPObj *obj, EC_NULL( volume->v_volcodepage = strdup(obj->options.volcodepage) ); /* mac charset is in [G] and [V] */ - if (val = getoption(obj->iniconfig, section, "mac charset", preset, NULL)) { + if ((val = getoption(obj->iniconfig, section, "mac charset", preset, NULL))) { if (strncasecmp(val, "MAC", 3) != 0) { LOG(log_warning, logtype_afpd, "Is '%s' really mac charset? ", val); } @@ -687,41 +668,41 @@ static struct vol *creatvol(AFPObj *obj, if(tmpname[i] == '/') tmpname[i] = ':'; bstring dbpath; - EC_NULL_LOG( val = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "vol dbpath", _PATH_STATEDIR "CNID/") ); - EC_NULL_LOG( dbpath = bformat("%s/%s/", val, tmpname) ); - EC_NULL_LOG( volume->v_dbpath = strdup(bdata(dbpath)) ); + EC_NULL( val = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "vol dbpath", _PATH_STATEDIR "CNID/") ); + EC_NULL( dbpath = bformat("%s/%s/", val, tmpname) ); + EC_NULL( volume->v_dbpath = strdup(cfrombstr(dbpath)) ); bdestroy(dbpath); - if (val = getoption(obj->iniconfig, section, "cnid scheme", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "cnid scheme", preset, NULL))) EC_NULL( volume->v_cnidscheme = strdup(val) ); else volume->v_cnidscheme = strdup(DEFAULT_CNID_SCHEME); - if (val = getoption(obj->iniconfig, section, "umask", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "umask", preset, NULL))) volume->v_umask = (int)strtol(val, NULL, 8); - if (val = getoption(obj->iniconfig, section, "directory perm", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "directory perm", preset, NULL))) volume->v_dperm = (int)strtol(val, NULL, 8); - if (val = getoption(obj->iniconfig, section, "file perm", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "file perm", preset, NULL))) volume->v_fperm = (int)strtol(val, NULL, 8); - if (val = getoption(obj->iniconfig, section, "vol size limit", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "vol size limit", preset, NULL))) volume->v_limitsize = (uint32_t)strtoul(val, NULL, 10); - if (val = getoption(obj->iniconfig, section, "preexec", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "preexec", preset, NULL))) EC_NULL( volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, section, "postexec", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "postexec", preset, NULL))) EC_NULL( volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, section, "root preexec", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "root preexec", preset, NULL))) EC_NULL( volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, section, "root postexec", preset, NULL)) + if ((val = getoption(obj->iniconfig, section, "root postexec", preset, NULL))) EC_NULL( volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, section, "appledouble", preset, NULL)) { + if ((val = getoption(obj->iniconfig, section, "appledouble", preset, NULL))) { if (strcmp(val, "v2") == 0) volume->v_adouble = AD_VERSION2; else if (strcmp(val, "ea") == 0) @@ -730,10 +711,10 @@ static struct vol *creatvol(AFPObj *obj, volume->v_adouble = AD_VERSION; } - if (val = getoption(obj->iniconfig, section, "cnid server", preset, NULL)) { + if ((val = getoption(obj->iniconfig, section, "cnid server", preset, NULL))) { EC_NULL( p = strdup(val) ); volume->v_cnidserver = p; - if (q = strrchr(val, ':')) { + if ((q = strrchr(val, ':'))) { *q++ = 0; volume->v_cnidport = strdup(q); } else { @@ -745,7 +726,7 @@ static struct vol *creatvol(AFPObj *obj, volume->v_cnidport = strdup(obj->options.Cnid_port); } - if (val = getoption(obj->iniconfig, section, "ea", preset, NULL)) { + if ((val = getoption(obj->iniconfig, section, "ea", preset, NULL))) { if (strcasecmp(val, "ad") == 0) volume->v_vfs_ea = AFPVOL_EA_AD; else if (strcasecmp(val, "sys") == 0) @@ -754,7 +735,7 @@ static struct vol *creatvol(AFPObj *obj, volume->v_vfs_ea = AFPVOL_EA_NONE; } - if (val = getoption(obj->iniconfig, section, "casefold", preset, NULL)) { + if ((val = getoption(obj->iniconfig, section, "casefold", preset, NULL))) { if (strcasecmp(val, "tolower") == 0) volume->v_casefold = AFPVOL_UMLOWER; else if (strcasecmp(val, "toupper") == 0) @@ -789,20 +770,14 @@ static struct vol *creatvol(AFPObj *obj, #endif if (!getoption_bool(obj->iniconfig, section, "convert appledouble", preset, 1)) volume->v_flags |= AFPVOL_NOV2TOEACONV; + if (getoption_bool(obj->iniconfig, section, "follow symlinks", preset, 0)) + volume->v_flags |= AFPVOL_FOLLOWSYM; if (getoption_bool(obj->iniconfig, section, "preexec close", preset, 0)) volume->v_preexec_close = 1; if (getoption_bool(obj->iniconfig, section, "root preexec close", preset, 0)) volume->v_root_preexec_close = 1; - /* Fixup for nested volume */ - if (new_vol_nested && strcmp(volume->v_cnidscheme, "last")) { - LOG(log_note, logtype_afpd, "volume \"%s\" is changed into cnid last and read only. path is nested: \"%s\"", - name, path); - free(volume->v_cnidscheme); - volume->v_cnidscheme = strdup("last"); - } - /* * Handle read-only behaviour. semantics: * 1) neither the rolist nor the rwlist exist -> rw @@ -824,6 +799,10 @@ static struct vol *creatvol(AFPObj *obj, volume->v_ad_options |= ADVOL_UNIXPRIV; if ((volume->v_flags & AFPVOL_INV_DOTS)) volume->v_ad_options |= ADVOL_INVDOTS; + if ((volume->v_flags & AFPVOL_FOLLOWSYM)) + volume->v_ad_options |= ADVOL_FOLLO_SYML; + if ((volume->v_flags & AFPVOL_RO)) + volume->v_ad_options |= ADVOL_RO; /* Mac to Unix conversion flags*/ if ((volume->v_flags & AFPVOL_EILSEQ)) @@ -849,7 +828,7 @@ static struct vol *creatvol(AFPObj *obj, /* Unicode Volume Name */ /* Firstly convert name from unixcharset to UTF8-MAC */ - flags = CONV_IGNORE | CONV_ALLOW_SLASH; + flags = CONV_IGNORE; tmpvlen = convert_charset(obj->options.unixcharset, CH_UTF8_MAC, 0, name, vlen, tmpname, AFPVOL_U8MNAMELEN, &flags); if (tmpvlen <= 0) { strcpy(tmpname, "???"); @@ -859,7 +838,7 @@ static struct vol *creatvol(AFPObj *obj, /* Do we have to mangle ? */ if ( (flags & CONV_REQMANGLE) || (tmpvlen > obj->options.volnamelen)) { if (tmpvlen + suffixlen > obj->options.volnamelen) { - flags = CONV_FORCE | CONV_ALLOW_SLASH; + flags = CONV_FORCE; tmpvlen = convert_charset(obj->options.unixcharset, CH_UTF8_MAC, 0, name, vlen, tmpname, obj->options.volnamelen - suffixlen, &flags); tmpname[tmpvlen >= 0 ? tmpvlen : 0] = 0; } @@ -875,7 +854,7 @@ static struct vol *creatvol(AFPObj *obj, /* Maccharset Volume Name */ /* Firsty convert name from unixcharset to maccharset */ - flags = CONV_IGNORE | CONV_ALLOW_SLASH; + flags = CONV_IGNORE; tmpvlen = convert_charset(obj->options.unixcharset, obj->options.maccharset, 0, name, vlen, tmpname, AFPVOL_U8MNAMELEN, &flags); if (tmpvlen <= 0) { strcpy(tmpname, "???"); @@ -885,7 +864,7 @@ static struct vol *creatvol(AFPObj *obj, /* Do we have to mangle ? */ if ( (flags & CONV_REQMANGLE) || (tmpvlen > AFPVOL_MACNAMELEN)) { if (tmpvlen + suffixlen > AFPVOL_MACNAMELEN) { - flags = CONV_FORCE | CONV_ALLOW_SLASH; + flags = CONV_FORCE; tmpvlen = convert_charset(obj->options.unixcharset, obj->options.maccharset, 0, @@ -939,16 +918,16 @@ static struct vol *creatvol(AFPObj *obj, initvol_vfs(volume); /* get/store uuid from file in afpd master*/ - if (!(pwd) && (volume->v_flags & AFPVOL_TM)) { - char *uuid = get_vol_uuid(obj, volume->v_localname); - if (!uuid) { - LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID", - volume->v_localname); - } else { - volume->v_uuid = uuid; - LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'", - volume->v_localname, volume->v_uuid); - } + become_root(); + char *uuid = get_vol_uuid(obj, volume->v_localname); + unbecome_root(); + if (!uuid) { + LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID", + volume->v_localname); + } else { + volume->v_uuid = uuid; + LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'", + volume->v_localname, volume->v_uuid); } /* no errors shall happen beyond this point because the cleanup would mess the volume chain up */ @@ -959,10 +938,8 @@ static struct vol *creatvol(AFPObj *obj, EC_CLEANUP: LOG(log_debug, logtype_afpd, "createvol: END: %d", ret); if (ret != 0) { - if (volume) { + if (volume) volume_free(volume); - free(volume); - } return NULL; } return volume; @@ -1003,9 +980,7 @@ static int readvolfile(AFPObj *obj, const struct passwd *pwent) char volname[AFPVOL_U8MNAMELEN + 1]; char path[MAXPATHLEN + 1], tmp[MAXPATHLEN + 1]; const char *preset, *default_preset, *p, *basedir; - char *q, *u; int i; - struct passwd *pw; regmatch_t match[1]; LOG(log_debug, logtype_afpd, "readvolfile: BEGIN"); @@ -1056,7 +1031,7 @@ static int readvolfile(AFPObj *obj, const struct passwd *pwent) continue; } - if (p = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "path", NULL)) { + if ((p = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "path", NULL))) { strlcat(tmp, "/", MAXPATHLEN); strlcat(tmp, p, MAXPATHLEN); } @@ -1097,7 +1072,7 @@ static int readvolfile(AFPObj *obj, const struct passwd *pwent) free(realvolpath); } -EC_CLEANUP: +// EC_CLEANUP: EC_EXIT; } @@ -1283,12 +1258,14 @@ void volume_unlink(struct vol *volume) } /*! - * Free all resources allocated in a struct vol, only struct dir *v_root can't be freed + * Free all resources allocated in a struct vol in load_volumes() + * + * Actually opening a volume (afp_openvol()) will allocate additional + * ressources which are freed in closevol() */ void volume_free(struct vol *vol) { - LOG(log_debug, logtype_afpd, "volume_free('%s'): BEGIN", vol->v_localname); - + free(vol->v_configname); free(vol->v_localname); free(vol->v_u8mname); free(vol->v_macname); @@ -1303,10 +1280,12 @@ void volume_free(struct vol *vol) free(vol->v_uuid); free(vol->v_cnidserver); free(vol->v_cnidport); + free(vol->v_preexec); free(vol->v_root_preexec); free(vol->v_postexec); + free(vol->v_root_postexec); - LOG(log_debug, logtype_afpd, "volume_free: END"); + free(vol); } /*! @@ -1335,7 +1314,7 @@ int load_charset(struct vol *vol) * @param obj (r) handle * @param delvol_fn (r) callback called for deleted volumes */ -int load_volumes(AFPObj *obj, void (*delvol_fn)(const AFPObj *obj, struct vol *)) +int load_volumes(AFPObj *obj) { EC_INIT; int fd = -1; @@ -1346,6 +1325,9 @@ int load_volumes(AFPObj *obj, void (*delvol_fn)(const AFPObj *obj, struct vol *) LOG(log_debug, logtype_afpd, "load_volumes: BEGIN"); + if (obj->uid) + pwent = getpwuid(obj->uid); + if (Volumes) { if (!volfile_changed(&obj->options)) goto EC_CLEANUP; @@ -1353,6 +1335,15 @@ int load_volumes(AFPObj *obj, void (*delvol_fn)(const AFPObj *obj, struct vol *) for (vol = Volumes; vol; vol = vol->v_next) { vol->v_deleted = 1; } + if (obj->uid) { + become_root(); + ret = set_groups(obj, pwent); + unbecome_root(); + if (ret != 0) { + LOG(log_error, logtype_afpd, "load_volumes: set_groups: %s", strerror(errno)); + EC_FAIL; + } + } } else { LOG(log_debug, logtype_afpd, "load_volumes: no volumes yet"); EC_ZERO_LOG( lstat(obj->options.configfile, &st) ); @@ -1377,9 +1368,6 @@ int load_volumes(AFPObj *obj, void (*delvol_fn)(const AFPObj *obj, struct vol *) break; } - if (obj->uid) - pwent = getpwuid(obj->uid); - if (obj->iniconfig) iniparser_freedict(obj->iniconfig); LOG(log_debug, logtype_afpd, "load_volumes: loading: %s", obj->options.configfile); @@ -1387,12 +1375,24 @@ int load_volumes(AFPObj *obj, void (*delvol_fn)(const AFPObj *obj, struct vol *) EC_ZERO_LOG( readvolfile(obj, pwent) ); - for ( vol = Volumes; vol; vol = vol->v_next ) { - if (vol->v_deleted) { + struct vol *p, *prevvol; + + vol = Volumes; + prevvol = NULL; + + while (vol) { + if (vol->v_deleted && !(vol->v_flags & AFPVOL_OPEN)) { LOG(log_debug, logtype_afpd, "load_volumes: deleted: %s", vol->v_localname); - if (delvol_fn) - delvol_fn(obj, vol); - vol = Volumes; + if (prevvol) + prevvol->v_next = vol->v_next; + else + Volumes = NULL; + p = vol->v_next; + volume_free(vol); + vol = p; + } else { + prevvol = vol; + vol = vol->v_next; } } @@ -1406,12 +1406,16 @@ EC_CLEANUP: void unload_volumes(AFPObj *obj) { - struct vol *vol; + struct vol *vol, *p; LOG(log_debug, logtype_afpd, "unload_volumes: BEGIN"); - for (vol = Volumes; vol; vol = vol->v_next) + p = Volumes; + while (p) { + vol = p; + p = vol->v_next; volume_free(vol); + } Volumes = NULL; obj->options.volfile.mtime = 0; @@ -1439,6 +1443,56 @@ struct vol *getvolbyvid(const uint16_t vid ) return( vol ); } +/* + * get username by path + * + * getvolbypath() assumes that the user home directory has the same name as the username. + * If that is not true, getuserbypath() is called and tries to retrieve the username + * from the directory owner, checking its validity. + * + * @param path (r) absolute volume path + * @returns NULL if no match is found, pointer to username if successfull + * + */ +static char *getuserbypath(const char *path) +{ + EC_INIT; + struct stat sbuf; + struct passwd *pwd; + char *hdir = NULL; + + LOG(log_debug, logtype_afpd, "getuserbypath(\"%s\")", path); + + /* does folder exists? */ + if (stat(path, &sbuf) != 0) + EC_FAIL; + + /* get uid of dir owner */ + if ((pwd = getpwuid(sbuf.st_uid)) == NULL) + EC_FAIL; + + /* does user home directory exists? */ + if (stat(pwd->pw_dir, &sbuf) != 0) + EC_FAIL; + + /* resolve and remove symlinks */ + if ((hdir = realpath_safe(pwd->pw_dir)) == NULL) + EC_FAIL; + + /* handle subdirectories, path = */ + if (strncmp(path, hdir, strlen(hdir)) != 0) + EC_FAIL; + + LOG(log_debug, logtype_afpd, "getuserbypath: match user: %s, home: %s, realhome: %s", + pwd->pw_name, pwd->pw_dir, hdir); + +EC_CLEANUP: + if (hdir) + free(hdir); + if (ret != 0) + return NULL; + return pwd->pw_name; +} /*! * Search volume by path, creating user home vols as necessary * @@ -1454,6 +1508,9 @@ struct vol *getvolbyvid(const uint16_t vid ) * (3) If there is, match "path" with "basedir regex" to get the user home parent dir * (4) Built user home path by appending the basedir matched in (3) and appending the username * (5) The next path element then is the username + * (5b) getvolbypath() assumes that the user home directory has the same name as the username. + * If that is not true, getuserbypath() is called and tries to retrieve the username + * from the directory owner, checking its validity * (6) Append [Homes]->path subdirectory if defined * (7) Create volume * @@ -1540,17 +1597,25 @@ struct vol *getvolbypath(AFPObj *obj, const char *path) p++; EC_NULL_LOG( user = strdup(p) ); - if (prw = strchr(user, '/')) + if ((prw = strchr(user, '/'))) *prw++ = 0; if (prw != 0) subpath = prw; strlcat(tmpbuf, user, MAXPATHLEN); + if (getpwnam(user) == NULL) { + /* (5b) */ + char *tuser; + if ((tuser = getuserbypath(tmpbuf)) != NULL) { + free(user); + user = strdup(tuser); + } + } strlcpy(obj->username, user, MAXUSERLEN); strlcat(tmpbuf, "/", MAXPATHLEN); /* (6) */ - if (subpathconfig = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "path", NULL)) { + if ((subpathconfig = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "path", NULL))) { /* if (!subpath || strncmp(subpathconfig, subpath, strlen(subpathconfig)) != 0) { EC_FAIL; @@ -1617,8 +1682,8 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) EC_INIT; dictionary *config; struct afp_options *options = &AFPObj->options; - int i, c; - const char *p, *tmp; + int c; + const char *p; char *q, *r; char val[MAXVAL]; @@ -1629,6 +1694,12 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->configfile = AFPObj->cmdlineconfigfile ? strdup(AFPObj->cmdlineconfigfile) : strdup(_PATH_CONFDIR "afp.conf"); options->sigconffile = strdup(_PATH_STATEDIR "afp_signature.conf"); options->uuidconf = strdup(_PATH_STATEDIR "afp_voluuid.conf"); +#ifdef HAVE_TRACKER_SPARQL + options->slmod_path = strdup(_PATH_AFPDUAMPATH "slmod_sparql.so"); +#endif +#ifdef HAVE_TRACKER_RDF + options->slmod_path = strdup(_PATH_AFPDUAMPATH "slmod_rdf.so"); +#endif options->flags = OPTION_UUID | AFPObj->cmdlineflags; if ((config = iniparser_load(AFPObj->options.configfile)) == NULL) @@ -1646,10 +1717,6 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->flags |= OPTION_NOZEROCONF; if (iniparser_getboolean(config, INISEC_GLOBAL, "advertise ssh", 0)) options->flags |= OPTION_ANNOUNCESSH; - if (iniparser_getboolean(config, INISEC_GLOBAL, "map acls", 1)) - options->flags |= OPTION_ACL2MACCESS; - if (iniparser_getboolean(config, INISEC_GLOBAL, "keep sessions", 0)) - options->flags |= OPTION_KEEPSESSIONS; if (iniparser_getboolean(config, INISEC_GLOBAL, "close vol", 0)) options->flags |= OPTION_CLOSEVOL; if (!iniparser_getboolean(config, INISEC_GLOBAL, "client polling", 0)) @@ -1658,8 +1725,12 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->flags |= OPTION_NOSENDFILE; if (iniparser_getboolean(config, INISEC_GLOBAL, "solaris share reservations", 1)) options->flags |= OPTION_SHARE_RESERV; + if (iniparser_getboolean(config, INISEC_GLOBAL, "afpstats", 0)) + options->flags |= OPTION_DBUS_AFPSTATS; if (iniparser_getboolean(config, INISEC_GLOBAL, "afp read locks", 0)) options->flags |= OPTION_AFP_READ_LOCK; + if (iniparser_getboolean(config, INISEC_GLOBAL, "spotlight", 0)) + options->flags |= OPTION_SPOTLIGHT; if (!iniparser_getboolean(config, INISEC_GLOBAL, "save password", 1)) options->passwdbits |= PASSWD_NOSAVE; if (iniparser_getboolean(config, INISEC_GLOBAL, "set password", 0)) @@ -1677,7 +1748,9 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->k5service = iniparser_getstrdup(config, INISEC_GLOBAL, "k5 service", NULL); options->k5realm = iniparser_getstrdup(config, INISEC_GLOBAL, "k5 realm", NULL); options->listen = iniparser_getstrdup(config, INISEC_GLOBAL, "afp listen", NULL); + options->interfaces = iniparser_getstrdup(config, INISEC_GLOBAL, "afp interfaces", NULL); options->ntdomain = iniparser_getstrdup(config, INISEC_GLOBAL, "nt domain", NULL); + options->addomain = iniparser_getstrdup(config, INISEC_GLOBAL, "ad domain", NULL); options->ntseparator = iniparser_getstrdup(config, INISEC_GLOBAL, "nt separator", NULL); options->mimicmodel = iniparser_getstrdup(config, INISEC_GLOBAL, "mimic model", NULL); options->adminauthuser = iniparser_getstrdup(config, INISEC_GLOBAL, "admin auth user",NULL); @@ -1694,6 +1767,19 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->fce_fmodwait = iniparser_getint (config, INISEC_GLOBAL, "fce holdfmod", 60); options->sleep = iniparser_getint (config, INISEC_GLOBAL, "sleep time", 10); options->disconnected = iniparser_getint (config, INISEC_GLOBAL, "disconnect time",24); + options->tracker_loglevel = iniparser_getint (config, INISEC_GLOBAL, "tracker loglevel", 1); + + p = iniparser_getstring(config, INISEC_GLOBAL, "map acls", "rights"); + if (STRCMP(p, ==, "rights")) + options->flags |= OPTION_ACL2MACCESS; + else if (STRCMP(p, ==, "mode")) + options->flags |= OPTION_ACL2MODE | OPTION_ACL2MACCESS; + else { + if (STRCMP(p, !=, "none")) { + LOG(log_error, logtype_afpd, "bad ACL mapping option: %s, defaulting to 'rights'", p); + options->flags |= OPTION_ACL2MACCESS; + } + } if ((p = iniparser_getstring(config, INISEC_GLOBAL, "hostname", NULL))) { EC_NULL_LOG( options->hostname = strdup(p) ); @@ -1763,11 +1849,11 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) LOG(log_debug, logtype_afpd, "Locale charset is '%s'", p); #else /* system doesn't have LOCALE support */ LOG(log_warning, logtype_afpd, "system doesn't have LOCALE support"); - p = strdup("UTF8"); + p = "UTF8"; #endif } if (strcasecmp(p, "UTF-8") == 0) { - p = strdup("UTF8"); + p = "UTF8"; } options->unixcodepage = strdup(p); set_charset_name(CH_UNIX, p); @@ -1780,7 +1866,7 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->volcodepage = strdup(options->unixcodepage); } else { if (strcasecmp(p, "UTF-8") == 0) { - p = strdup("UTF8"); + p = "UTF8"; } options->volcodepage = strdup(p); } @@ -1824,3 +1910,84 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) EC_CLEANUP: EC_EXIT; } + +#define CONFIG_ARG_FREE(a) do { \ + free(a); \ + a = NULL; \ + } while (0); + +/* get rid of any allocated afp_option buffers. */ +void afp_config_free(AFPObj *obj) +{ + if (obj->options.configfile) + CONFIG_ARG_FREE(obj->options.configfile); + if (obj->options.sigconffile) + CONFIG_ARG_FREE(obj->options.sigconffile); + if (obj->options.uuidconf) + CONFIG_ARG_FREE(obj->options.uuidconf); + if (obj->options.logconfig) + CONFIG_ARG_FREE(obj->options.logconfig); + if (obj->options.logfile) + CONFIG_ARG_FREE(obj->options.logfile); + if (obj->options.loginmesg) + CONFIG_ARG_FREE(obj->options.loginmesg); + if (obj->options.guest) + CONFIG_ARG_FREE(obj->options.guest); + if (obj->options.extmapfile) + CONFIG_ARG_FREE(obj->options.extmapfile); + if (obj->options.passwdfile) + CONFIG_ARG_FREE(obj->options.passwdfile); + if (obj->options.uampath) + CONFIG_ARG_FREE(obj->options.uampath); + if (obj->options.uamlist) + CONFIG_ARG_FREE(obj->options.uamlist); + if (obj->options.port) + CONFIG_ARG_FREE(obj->options.port); + if (obj->options.signatureopt) + CONFIG_ARG_FREE(obj->options.signatureopt); + if (obj->options.k5service) + CONFIG_ARG_FREE(obj->options.k5service); + if (obj->options.k5realm) + CONFIG_ARG_FREE(obj->options.k5realm); + if (obj->options.listen) + CONFIG_ARG_FREE(obj->options.listen); + if (obj->options.interfaces) + CONFIG_ARG_FREE(obj->options.interfaces); + if (obj->options.ntdomain) + CONFIG_ARG_FREE(obj->options.ntdomain); + if (obj->options.addomain) + CONFIG_ARG_FREE(obj->options.addomain); + if (obj->options.ntseparator) + CONFIG_ARG_FREE(obj->options.ntseparator); + if (obj->options.mimicmodel) + CONFIG_ARG_FREE(obj->options.mimicmodel); + if (obj->options.adminauthuser) + CONFIG_ARG_FREE(obj->options.adminauthuser); + if (obj->options.hostname) + CONFIG_ARG_FREE(obj->options.hostname); + if (obj->options.k5keytab) + CONFIG_ARG_FREE(obj->options.k5keytab); + if (obj->options.Cnid_srv) + CONFIG_ARG_FREE(obj->options.Cnid_srv); + if (obj->options.Cnid_port) + CONFIG_ARG_FREE(obj->options.Cnid_port); + if (obj->options.fqdn) + CONFIG_ARG_FREE(obj->options.fqdn); + if (obj->options.slmod_path) + CONFIG_ARG_FREE(obj->options.slmod_path); + + if (obj->options.unixcodepage) + CONFIG_ARG_FREE(obj->options.unixcodepage); + if (obj->options.maccodepage) + CONFIG_ARG_FREE(obj->options.maccodepage); + if (obj->options.volcodepage) + CONFIG_ARG_FREE(obj->options.volcodepage); + + obj->options.flags = 0; + obj->options.passwdbits = 0; + + /* Free everything called from afp_config_parse() */ + free_extmap(); + iniparser_freedict(obj->iniconfig); + free_charset_names(); +}