static struct vol *Volumes = NULL;
static uint16_t lastvid = 0;
+
+/*
+ * Normalize volume path
+ */
+static char *realpath_safe(const char *path)
+{
+ char *resolved_path;
+
+#ifdef REALPATH_TAKES_NULL
+ if ((resolved_path = realpath(path, NULL)) == NULL) {
+ LOG(log_error, logtype_afpd, "realpath() cannot resolve path \"%s\"", path);
+ return NULL;
+ }
+ return resolved_path;
+
+#else
+if ((resolved_path = malloc(MAXPATHLEN+1)) == NULL)
+ return NULL;
+ if (realpath(path, resolved_path) == NULL) {
+ free(resolved_path);
+ LOG(log_error, logtype_afpd, "realpath() cannot resolve path \"%s\"", path);
+ return NULL;
+ }
+ /* Safe some memory */
+ char *tmp;
+ if ((tmp = strdup(resolved_path)) == NULL) {
+ free(resolved_path);
+ return NULL;
+ }
+ free(resolved_path);
+ resolved_path = tmp;
+ return resolved_path;
+#endif
+}
+
+
/*
* Get a volumes UUID from the config file.
* If there is none, it is generated and stored there.
{
EC_INIT;
struct vol *volume = NULL;
- int suffixlen, vlen, tmpvlen, u8mvlen, macvlen;
- char tmpname[AFPVOL_U8MNAMELEN+1];
+ int i, suffixlen, vlen, tmpvlen, u8mvlen, macvlen;
+ char *tmpname;
ucs2_t u8mtmpname[(AFPVOL_U8MNAMELEN+1)*2], mactmpname[(AFPVOL_MACNAMELEN+1)*2];
char suffix[6]; /* max is #FFFF */
uint16_t flags;
else
EC_NULL( volume->v_maccodepage = strdup(obj->options.maccodepage) );
+ vlen = strlen(name);
+ tmpname = strdup(name);
+ for(i = 0; i < vlen; i++)
+ 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, name) );
+ EC_NULL_LOG( dbpath = bformat("%s/%s/", val, tmpname) );
EC_NULL_LOG( volume->v_dbpath = strdup(bdata(dbpath)) );
bdestroy(dbpath);
/* because v_vid has not been decided yet. */
suffixlen = sprintf(suffix, "#%X", lastvid + 1 );
-
- vlen = strlen( name );
-
/* Unicode Volume Name */
/* Firstly convert name from unixcharset to UTF8-MAC */
- flags = CONV_IGNORE;
+ flags = CONV_IGNORE | CONV_ALLOW_SLASH;
tmpvlen = convert_charset(obj->options.unixcharset, CH_UTF8_MAC, 0, name, vlen, tmpname, AFPVOL_U8MNAMELEN, &flags);
if (tmpvlen <= 0) {
strcpy(tmpname, "???");
/* Do we have to mangle ? */
if ( (flags & CONV_REQMANGLE) || (tmpvlen > obj->options.volnamelen)) {
if (tmpvlen + suffixlen > obj->options.volnamelen) {
- flags = CONV_FORCE;
+ flags = CONV_FORCE | CONV_ALLOW_SLASH;
tmpvlen = convert_charset(obj->options.unixcharset, CH_UTF8_MAC, 0, name, vlen, tmpname, obj->options.volnamelen - suffixlen, &flags);
tmpname[tmpvlen >= 0 ? tmpvlen : 0] = 0;
}
/* Maccharset Volume Name */
/* Firsty convert name from unixcharset to maccharset */
- flags = CONV_IGNORE;
+ flags = CONV_IGNORE | CONV_ALLOW_SLASH;
tmpvlen = convert_charset(obj->options.unixcharset, obj->options.maccharset, 0, name, vlen, tmpname, AFPVOL_U8MNAMELEN, &flags);
if (tmpvlen <= 0) {
strcpy(tmpname, "???");
/* Do we have to mangle ? */
if ( (flags & CONV_REQMANGLE) || (tmpvlen > AFPVOL_MACNAMELEN)) {
if (tmpvlen + suffixlen > AFPVOL_MACNAMELEN) {
- flags = CONV_FORCE;
+ flags = CONV_FORCE | CONV_ALLOW_SLASH;
tmpvlen = convert_charset(obj->options.unixcharset,
obj->options.maccharset,
0,
EC_INIT;
static int regexerr = -1;
static regex_t reg;
- char path[MAXPATHLEN + 1];
+ char *realpw_dir;
+ char *realvolpath;
char volname[AFPVOL_U8MNAMELEN + 1];
- char tmp[MAXPATHLEN + 1];
+ char tmp[MAXPATHLEN + 1], tmp2[MAXPATHLEN + 1];
const char *preset, *default_preset, *p, *basedir;
char *q, *u;
int i;
if (pwent->pw_dir == NULL || STRCMP("", ==, pwent->pw_dir))
/* no user home */
continue;
+ if ((realpw_dir = realpath_safe(pwent->pw_dir)) == NULL)
+ continue;
/* check if user home matches our "basedir regex" */
if ((basedir = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "basedir regex", NULL)) == NULL) {
LOG(log_debug, logtype_default, "readvolfile: bad basedir regex: %s", errbuf);
}
- if (regexec(®, pwent->pw_dir, 1, match, 0) == REG_NOMATCH) {
+ if (regexec(®, realpw_dir, 1, match, 0) == REG_NOMATCH) {
LOG(log_debug, logtype_default, "readvolfile: user home \"%s\" doesn't match basedir regex \"%s\"",
- pwent->pw_dir, basedir);
+ realpw_dir, basedir);
continue;
}
- strlcpy(tmp, pwent->pw_dir, MAXPATHLEN);
+ strlcpy(tmp, realpw_dir, MAXPATHLEN);
strlcat(tmp, "/", MAXPATHLEN);
if (p = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "path", NULL))
strlcat(tmp, p, MAXPATHLEN);
strlcpy(tmp, p, MAXPATHLEN);
}
- if (volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL) == NULL)
+ if (volxlate(obj, tmp2, sizeof(tmp2) - 1, tmp, pwent, NULL, NULL) == NULL)
continue;
/* do variable substitution for volume name */
LOG(log_warning, logtype_afpd, "home name must contain $u.");
p = "$u's home";
}
+ if (strchr(p, ':') != NULL) {
+ LOG(log_warning, logtype_afpd, "home name must not contain \":\".");
+ p = "$u's home";
+ }
strlcpy(tmp, p, MAXPATHLEN);
} else {
strlcpy(tmp, secname, AFPVOL_U8MNAMELEN);
}
- if (volxlate(obj, volname, sizeof(volname) - 1, tmp, pwent, path, NULL) == NULL)
+ if (volxlate(obj, volname, sizeof(volname) - 1, tmp, pwent, tmp2, NULL) == NULL)
continue;
preset = iniparser_getstring(obj->iniconfig, secname, "vol preset", NULL);
- creatvol(obj, pwent, secname, volname, path, preset ? preset : default_preset ? default_preset : NULL);
+ if ((realvolpath = realpath_safe(tmp2)) == NULL)
+ continue;
+
+ creatvol(obj, pwent, secname, volname, realvolpath, preset ? preset : default_preset ? default_preset : NULL);
}
EC_CLEANUP:
const struct passwd *pw;
char volname[AFPVOL_U8MNAMELEN + 1];
char abspath[MAXPATHLEN + 1];
- char volpath[MAXPATHLEN + 1];
+ char volpath[MAXPATHLEN + 1], *realvolpath;
char tmpbuf[MAXPATHLEN + 1];
const char *secname, *basedir, *p = NULL, *subpath = NULL, *subpathconfig;
char *user = NULL, *prw;
/* (6) */
if (subpathconfig = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "path", NULL)) {
+ /*
if (!subpath || strncmp(subpathconfig, subpath, strlen(subpathconfig)) != 0) {
EC_FAIL;
}
+ */
strlcat(tmpbuf, subpathconfig, MAXPATHLEN);
strlcat(tmpbuf, "/", MAXPATHLEN);
}
if (volxlate(obj, volpath, sizeof(volpath) - 1, tmpbuf, pw, NULL, NULL) == NULL)
return NULL;
+ if ((realvolpath = realpath_safe(volpath)) == NULL)
+ return NULL;
+
EC_NULL( pw = getpwnam(user) );
- LOG(log_debug, logtype_afpd, "getvolbypath(\"%s\"): user: %s, homedir: %s => volpath: \"%s\"",
- path, user, pw->pw_dir, volpath);
+ LOG(log_debug, logtype_afpd, "getvolbypath(\"%s\"): user: %s, homedir: %s => realvolpath: \"%s\"",
+ path, user, pw->pw_dir, realvolpath);
/* do variable substitution for volume name */
p = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "home name", "$u's home");
if (strstr(p, "$u") == NULL)
p = "$u's home";
strlcpy(tmpbuf, p, AFPVOL_U8MNAMELEN);
- EC_NULL_LOG( volxlate(obj, volname, sizeof(volname) - 1, tmpbuf, pw, volpath, NULL) );
+ EC_NULL_LOG( volxlate(obj, volname, sizeof(volname) - 1, tmpbuf, pw, realvolpath, NULL) );
const char *preset, *default_preset;
default_preset = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "vol preset", NULL);
preset = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "vol preset", NULL);
- vol = creatvol(obj, pw, INISEC_HOMES, volname, volpath, preset ? preset : default_preset ? default_preset : NULL);
+ vol = creatvol(obj, pw, INISEC_HOMES, volname, realvolpath, preset ? preset : default_preset ? default_preset : NULL);
EC_CLEANUP:
if (user)