From b14967f5bbdc7301617fe732174bb3deaee9512c Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Wed, 29 Feb 2012 16:26:51 +0100 Subject: [PATCH] Support for home dirs --- bin/ad/ad.c | 10 +- bin/ad/ad.h | 14 +- bin/ad/ad_cp.c | 6 +- bin/ad/ad_find.c | 4 +- bin/ad/ad_ls.c | 8 +- bin/ad/ad_mv.c | 8 +- bin/ad/ad_rm.c | 4 +- bin/ad/ad_util.c | 10 +- etc/cnid_dbd/cmd_dbd.c | 2 +- etc/cnid_dbd/cnid_metad.c | 34 +++-- etc/cnid_dbd/main.c | 2 +- include/atalk/globals.h | 1 + include/atalk/netatalk_conf.h | 3 +- include/atalk/volume.h | 4 +- libatalk/util/netatalk_conf.c | 250 ++++++++++++++++++++++++---------- 15 files changed, 239 insertions(+), 121 deletions(-) diff --git a/bin/ad/ad.c b/bin/ad/ad.c index ea312fa9..6115c2f2 100644 --- a/bin/ad/ad.c +++ b/bin/ad/ad.c @@ -62,15 +62,15 @@ int main(int argc, char **argv) return 1; if (STRCMP(argv[1], ==, "ls")) - return ad_ls(argc - 1, argv + 1); + return ad_ls(argc - 1, argv + 1, &obj); else if (STRCMP(argv[1], ==, "cp")) - return ad_cp(argc - 1, argv + 1); + return ad_cp(argc - 1, argv + 1, &obj); else if (STRCMP(argv[1], ==, "rm")) - return ad_rm(argc - 1, argv + 1); + return ad_rm(argc - 1, argv + 1, &obj); else if (STRCMP(argv[1], ==, "mv")) - return ad_mv(argc, argv); + return ad_mv(argc, argv, &obj); else if (STRCMP(argv[1], ==, "find")) - return ad_find(argc, argv); + return ad_find(argc, argv, &obj); else if (STRCMP(argv[1], ==, "-v")) { show_version(); return 1; diff --git a/bin/ad/ad.h b/bin/ad/ad.h index d97f4b06..fcfe1220 100644 --- a/bin/ad/ad.h +++ b/bin/ad/ad.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -56,14 +57,15 @@ typedef struct { extern int log_verbose; /* Logging flag */ extern void _log(enum logtype lt, char *fmt, ...); -extern int ad_ls(int argc, char **argv); -extern int ad_cp(int argc, char **argv); -extern int ad_rm(int argc, char **argv); -extern int ad_mv(int argc, char **argv); -extern int ad_find(int argc, char **argv); +extern int ad_ls(int argc, char **argv, AFPObj *obj); +extern int ad_cp(int argc, char **argv, AFPObj *obj); + +extern int ad_rm(int argc, char **argv, AFPObj *obj); +extern int ad_mv(int argc, char **argv, AFPObj *obj); +extern int ad_find(int argc, char **argv, AFPObj *obj); /* ad_util.c */ -extern int openvol(const char *path, afpvol_t *vol); +extern int openvol(AFPObj *obj, const char *path, afpvol_t *vol); extern void closevol(afpvol_t *vol); extern cnid_t cnid_for_path(const afpvol_t *vol, const char *path, cnid_t *did); extern cnid_t cnid_for_paths_parent(const afpvol_t *vol, const char *path, cnid_t *did); diff --git a/bin/ad/ad_cp.c b/bin/ad/ad_cp.c index 40500441..8f14e3f1 100644 --- a/bin/ad/ad_cp.c +++ b/bin/ad/ad_cp.c @@ -211,7 +211,7 @@ static void usage_cp(void) exit(EXIT_FAILURE); } -int ad_cp(int argc, char *argv[]) +int ad_cp(int argc, char *argv[], AFPObj *obj) { struct stat to_stat, tmp_stat; int r, ch, have_trailing_slash; @@ -351,11 +351,11 @@ int ad_cp(int argc, char *argv[]) #endif /* Load .volinfo file for destination*/ - openvol(to.p_path, &dvolume); + openvol(obj, to.p_path, &dvolume); for (int i = 0; argv[i] != NULL; i++) { /* Load .volinfo file for source */ - openvol(argv[i], &svolume); + openvol(obj, argv[i], &svolume); if (nftw(argv[i], copy, upfunc, 20, ftw_options) == -1) { if (alarmed) { diff --git a/bin/ad/ad_find.c b/bin/ad/ad_find.c index 20c67afb..88a46752 100644 --- a/bin/ad/ad_find.c +++ b/bin/ad/ad_find.c @@ -82,7 +82,7 @@ static void usage_find(void) ); } -int ad_find(int argc, char **argv) +int ad_find(int argc, char **argv, AFPObj *obj) { int c, ret; afpvol_t vol; @@ -111,7 +111,7 @@ int ad_find(int argc, char **argv) set_signal(); cnid_init(); - if (openvol(srchvol, &vol) != 0) + if (openvol(obj, srchvol, &vol) != 0) ERROR("Cant open volume \"%s\"", srchvol); uint16_t flags = CONV_TOLOWER; diff --git a/bin/ad/ad_ls.c b/bin/ad/ad_ls.c index 8cda318a..d8362595 100644 --- a/bin/ad/ad_ls.c +++ b/bin/ad/ad_ls.c @@ -594,7 +594,7 @@ exit: return ret; } -int ad_ls(int argc, char **argv) +int ad_ls(int argc, char **argv, AFPObj *obj) { int c, firstarg; afpvol_t vol; @@ -630,7 +630,7 @@ int ad_ls(int argc, char **argv) cnid_init(); if ((argc - optind) == 0) { - openvol(".", &vol); + openvol(obj, ".", &vol); ad_ls_r(".", &vol); closevol(&vol); } @@ -650,7 +650,7 @@ int ad_ls(int argc, char **argv) first = 1; recursion = 0; - openvol(argv[optind], &vol); + openvol(obj, argv[optind], &vol); ad_ls_r(argv[optind], &vol); closevol(&vol); next: @@ -672,7 +672,7 @@ int ad_ls(int argc, char **argv) first = 1; recursion = 0; - openvol(argv[optind], &vol); + openvol(obj, argv[optind], &vol); ad_ls_r(argv[optind], &vol); closevol(&vol); diff --git a/bin/ad/ad_mv.c b/bin/ad/ad_mv.c index 6991b276..7f592dd2 100644 --- a/bin/ad/ad_mv.c +++ b/bin/ad/ad_mv.c @@ -139,7 +139,7 @@ static void usage_mv(void) exit(EXIT_FAILURE); } -int ad_mv(int argc, char *argv[]) +int ad_mv(int argc, char *argv[], AFPObj *obj) { size_t baselen, len; int rval; @@ -184,7 +184,7 @@ int ad_mv(int argc, char *argv[]) set_signal(); cnid_init(); - if (openvol(argv[argc - 1], &dvolume) != 0) { + if (openvol(obj, argv[argc - 1], &dvolume) != 0) { SLOG("Error opening CNID database for source \"%s\": ", argv[argc - 1]); return 1; } @@ -196,7 +196,7 @@ int ad_mv(int argc, char *argv[]) if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) { if (argc > 2) usage_mv(); - if (openvol(argv[0], &svolume) != 0) { + if (openvol(obj, argv[0], &svolume) != 0) { SLOG("Error opening CNID database for destination \"%s\": ", argv[0]); return 1; } @@ -234,7 +234,7 @@ int ad_mv(int argc, char *argv[]) rval = 1; } else { memmove(endp, p, (size_t)len + 1); - openvol(*argv, &svolume); + openvol(obj, *argv, &svolume); if (do_move(*argv, path)) rval = 1; diff --git a/bin/ad/ad_rm.c b/bin/ad/ad_rm.c index e65d6f27..195fee06 100644 --- a/bin/ad/ad_rm.c +++ b/bin/ad/ad_rm.c @@ -132,7 +132,7 @@ static void usage_rm(void) exit(EXIT_FAILURE); } -int ad_rm(int argc, char *argv[]) +int ad_rm(int argc, char *argv[], AFPObj *obj) { int ch; @@ -165,7 +165,7 @@ int ad_rm(int argc, char *argv[]) for (int i = 0; argv[i] != NULL; i++) { /* Load .volinfo file for source */ - openvol(argv[i], &volume); + openvol(obj, argv[i], &volume); if (nftw(argv[i], rm, upfunc, 20, FTW_DEPTH | FTW_PHYS) == -1) { if (alarmed) { diff --git a/bin/ad/ad_util.c b/bin/ad/ad_util.c index d7e9fee5..0143a1e4 100644 --- a/bin/ad/ad_util.c +++ b/bin/ad/ad_util.c @@ -64,8 +64,10 @@ #include #include #include +#include #include + #include "ad.h" int log_verbose; /* Logging flag */ @@ -96,21 +98,21 @@ void _log(enum logtype lt, char *fmt, ...) * * @returns 0 on success, exits on error */ -int openvol(const char *path, afpvol_t *vol) +int openvol(AFPObj *obj, const char *path, afpvol_t *vol) { int flags = 0; memset(vol, 0, sizeof(afpvol_t)); - /* try to find a .AppleDesktop/.volinfo */ - if ((vol->vol = getvolbypath(path)) == NULL) + if ((vol->vol = getvolbypath(obj, path)) == NULL) return -1; if (STRCMP(vol->vol->v_cnidscheme, != , "dbd")) ERROR("\"%s\" isn't a \"dbd\" CNID volume!", vol->vol->v_path); /* Sanity checks to ensure we can touch this volume */ - if (vol->vol->v_adouble != AD_VERSION2) + if (vol->vol->v_adouble != AD_VERSION2 + && vol->vol->v_adouble != AD_VERSION_EA) ERROR("Unsupported adouble versions: %u", vol->vol->v_adouble); if (vol->vol->v_vfs_ea != AFPVOL_EA_SYS) diff --git a/etc/cnid_dbd/cmd_dbd.c b/etc/cnid_dbd/cmd_dbd.c index d197efd5..7a1614f7 100644 --- a/etc/cnid_dbd/cmd_dbd.c +++ b/etc/cnid_dbd/cmd_dbd.c @@ -268,7 +268,7 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - if ((vol = getvolbypath(volpath)) == NULL) { + if ((vol = getvolbypath(&obj, volpath)) == NULL) { dbd_log( LOGSTD, "Couldn't find volume for '%s'", volpath); exit(EXIT_FAILURE); } diff --git a/etc/cnid_dbd/cnid_metad.c b/etc/cnid_dbd/cnid_metad.c index c7426713..0f6e07a2 100644 --- a/etc/cnid_dbd/cnid_metad.c +++ b/etc/cnid_dbd/cnid_metad.c @@ -113,7 +113,7 @@ static uint maxvol; #define DEFAULTPORT "4700" struct server { - struct vol *vol; + char *v_path; pid_t pid; time_t tm; /* When respawned last */ int count; /* Times respawned in the last TESTTIME secondes */ @@ -141,15 +141,12 @@ static void sigterm_handler(int sig) daemon_exit(0); } -static struct server *test_usockfn(const struct vol *vol) +static struct server *test_usockfn(const char *path) { int i; - if (!(vol->v_flags & AFPVOL_OPEN)) - return NULL; - for (i = 0; i < maxvol; i++) { - if (vol->v_vid == srv[i].vol->v_vid) + if (srv[i].v_path && STRCMP(path, ==, srv[i].v_path)) return &srv[i]; } @@ -157,7 +154,7 @@ static struct server *test_usockfn(const struct vol *vol) } /* -------------------- */ -static int maybe_start_dbd(const AFPObj *obj, char *dbdpn, struct vol *vol) +static int maybe_start_dbd(const AFPObj *obj, char *dbdpn, const char *volpath) { pid_t pid; struct server *up; @@ -166,13 +163,13 @@ static int maybe_start_dbd(const AFPObj *obj, char *dbdpn, struct vol *vol) time_t t; char buf1[8]; char buf2[8]; - char *volpath = vol->v_path; - LOG(log_debug, logtype_cnid, "maybe_start_dbd: Volume: \"%s\"", volpath); + LOG(log_debug, logtype_cnid, "maybe_start_dbd(\"%s\"): BEGIN", volpath); - up = test_usockfn(vol); + up = test_usockfn(volpath); if (up && up->pid) { /* we already have a process, send our fd */ + LOG(log_debug, logtype_cnid, "maybe_start_dbd: cnid_dbd[%d] already serving", up->pid); if (send_fd(up->control_fd, rqstfd) < 0) { /* FIXME */ return -1; @@ -180,16 +177,16 @@ static int maybe_start_dbd(const AFPObj *obj, char *dbdpn, struct vol *vol) return 0; } - LOG(log_maxdebug, logtype_cnid, "maybe_start_dbd: no cnid_dbd for that volume yet"); + LOG(log_debug, logtype_cnid, "maybe_start_dbd: no cnid_dbd serving yet"); time(&t); if (!up) { /* find an empty slot (i < maxvol) or the first free slot (i == maxvol)*/ for (i = 0; i <= maxvol; i++) { - if (srv[i].vol == NULL && i < MAXVOLS) { + if (srv[i].v_path == NULL && i < MAXVOLS) { up = &srv[i]; - up->vol = vol; - vol->v_flags |= AFPVOL_OPEN; + if ((up->v_path = strdup(volpath)) == NULL) + return -1; up->tm = t; up->count = 0; if (i == maxvol) @@ -261,7 +258,7 @@ static int maybe_start_dbd(const AFPObj *obj, char *dbdpn, struct vol *vol) /* there's a pb with the db inform child, it will delete the db */ LOG(log_warning, logtype_cnid, "Multiple attempts to start CNID db daemon for \"%s\" failed, wiping the slate clean...", - up->vol->v_path); + up->v_path); ret = execlp(dbdpn, dbdpn, "-F", obj->options.configfile, "-p", volpath, "-t", buf1, "-l", buf2, "-d", NULL); } else { ret = execlp(dbdpn, dbdpn, "-F", obj->options.configfile, "-p", volpath, "-t", buf1, "-l", buf2, NULL); @@ -533,7 +530,8 @@ int main(int argc, char *argv[]) if (srv[i].pid == pid) { srv[i].pid = 0; close(srv[i].control_fd); - srv[i].vol->v_flags &= ~AFPVOL_OPEN; + free(srv[i].v_path); + srv[i].v_path = NULL; break; } } @@ -590,7 +588,7 @@ int main(int argc, char *argv[]) goto loop_end; } - if ((vol = getvolbypath(volpath)) == NULL) { + if ((vol = getvolbypath(&obj, volpath)) == NULL) { LOG(log_severe, logtype_cnid, "main: no volume for path \"%s\"", volpath); goto loop_end; } @@ -599,7 +597,7 @@ int main(int argc, char *argv[]) goto loop_end; } - maybe_start_dbd(&obj, dbdpn, vol); + maybe_start_dbd(&obj, dbdpn, vol->v_path); loop_end: close(rqstfd); } diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c index fea36b81..1079fb58 100644 --- a/etc/cnid_dbd/main.c +++ b/etc/cnid_dbd/main.c @@ -318,7 +318,7 @@ int main(int argc, char *argv[]) setuplog(obj.options.logconfig, obj.options.logfile); EC_ZERO( load_volumes(&obj, NULL) ); - EC_NULL( vol = getvolbypath(volpath) ); + EC_NULL( vol = getvolbypath(&obj, volpath) ); EC_ZERO( load_charset(vol) ); pack_setvol(vol); diff --git a/include/atalk/globals.h b/include/atalk/globals.h index 60ba4ffb..c6b8eb28 100644 --- a/include/atalk/globals.h +++ b/include/atalk/globals.h @@ -54,6 +54,7 @@ **********************************************************************************************/ #define INISEC_GLOBAL "Global" +#define INISEC_HOMES "Homes" struct DSI; #define AFPOBJ_TMPSIZ (MAXPATHLEN) diff --git a/include/atalk/netatalk_conf.h b/include/atalk/netatalk_conf.h index 9c189e63..5715df74 100644 --- a/include/atalk/netatalk_conf.h +++ b/include/atalk/netatalk_conf.h @@ -27,7 +27,8 @@ extern int load_volumes(AFPObj *obj, void (*delvol_fn)(struct vol *)); extern void unload_volumes(AFPObj *obj); extern struct vol *getvolumes(void); extern struct vol *getvolbyvid(const uint16_t); -extern struct vol *getvolbypath(const char *path); +extern struct vol *getvolbypath(AFPObj *obj, const char *path); +extern struct vol *getvolbyname(const char *name); extern void volume_free(struct vol *vol); extern void volume_unlink(struct vol *volume); #endif diff --git a/include/atalk/volume.h b/include/atalk/volume.h index 18a841a8..6ae66baa 100644 --- a/include/atalk/volume.h +++ b/include/atalk/volume.h @@ -70,7 +70,8 @@ struct vol { /* only when opening/closing volumes or in error */ int v_casefold; - char *v_localname; /* as defined in AppleVolumes.default */ + char *v_configname; /* as defined in afpc.conf */ + char *v_localname; /* as defined in afp.conf but with vars expanded */ char *v_volcodepage; char *v_maccodepage; char *v_password; @@ -112,6 +113,7 @@ struct vol { Keep in sync with libatalk/util/volinfo.c */ #define AFPVOL_NOV2TOEACONV (1 << 5) /* no adouble:v2 to adouble:ea conversion */ +#define AFPVOL_UNIX_CTXT (1 << 6) /* volume created by getvolbypath ie UNIX access, not afpd AFP user session */ #define AFPVOL_RO (1 << 8) /* read-only volume */ #define AFPVOL_NOHEX (1 << 10) /* don't do :hex translation */ #define AFPVOL_USEDOTS (1 << 11) /* use real dots */ diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index 805a9ad0..507bd210 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -52,6 +52,7 @@ * Locals **************************************************************/ +static int have_uservol = 0; /* whether there's generic user home share in config ("~" or "~/path", but not "~user") */ static struct vol *Volumes = NULL; static uint16_t lastvid = 0; @@ -320,8 +321,6 @@ static char *volxlate(const AFPObj *obj, /* now figure out what the variable is */ q = NULL; if (IS_VAR(p, "$b")) { - if (!obj->uid && xlatevolname) - return NULL; if (path) { if ((q = strrchr(path, '/')) == NULL) q = path; @@ -329,8 +328,6 @@ static char *volxlate(const AFPObj *obj, q++; } } else if (IS_VAR(p, "$c")) { - if (!obj->uid && xlatevolname) - return NULL; DSI *dsi = obj->dsi; len = sprintf(dest, "%s:%u", getip_string((struct sockaddr *)&dsi->client), @@ -338,41 +335,29 @@ static char *volxlate(const AFPObj *obj, dest += len; destlen -= len; } else if (IS_VAR(p, "$d")) { - if (!obj->uid && xlatevolname) - return NULL; q = path; } else if (pwd && IS_VAR(p, "$f")) { - if (!obj->uid && xlatevolname) - return NULL; if ((r = strchr(pwd->pw_gecos, ','))) *r = '\0'; q = pwd->pw_gecos; } else if (pwd && IS_VAR(p, "$g")) { - if (!obj->uid && xlatevolname) - return NULL; struct group *grp = getgrgid(pwd->pw_gid); if (grp) q = grp->gr_name; } else if (IS_VAR(p, "$h")) { q = obj->options.hostname; } else if (IS_VAR(p, "$i")) { - if (!obj->uid && xlatevolname) - return NULL; DSI *dsi = obj->dsi; q = getip_string((struct sockaddr *)&dsi->client); } else if (IS_VAR(p, "$s")) { q = obj->options.hostname; } else if (obj->username && IS_VAR(p, "$u")) { - if (!obj->uid && xlatevolname) - return NULL; char* sep = NULL; if ( obj->options.ntseparator && (sep = strchr(obj->username, obj->options.ntseparator[0])) != NULL) q = sep+1; else q = obj->username; } else if (IS_VAR(p, "$v")) { - if (!obj->uid && xlatevolname) - return NULL; if (volname) { q = volname; } @@ -507,7 +492,7 @@ static int hostaccessvol(const AFPObj *obj, const char *volname, const char *arg * Get option string from config, use default value if not set * * @param conf (r) config handle - * @param vol (r) volume name + * @param vol (r) volume name (must be section name ie wo vars expanded) * @param opt (r) option * @param def (r) if "option" is not found in "name", try to find it in section "def" * @@ -530,16 +515,18 @@ EC_CLEANUP: * * @param obj (r) handle * @param pwd (r) struct passwd of logged in user, may be NULL in master afpd - * @param path (r) volume path + * @param section (r) volume name wo variables expanded (exactly as in iniconfig) * @param name (r) volume name + * @param path (r) volume path * @param preset (r) default preset, may be NULL - * @returns 0 on success, -1 on error + * @returns vol on success, NULL on error */ -static int creatvol(AFPObj *obj, - const struct passwd *pwd, - const char *path, - const char *name, - const char *preset) +static struct vol *creatvol(AFPObj *obj, + const struct passwd *pwd, + const char *section, + const char *name, + const char *path, + const char *preset) { EC_INIT; struct vol *volume = NULL; @@ -566,9 +553,10 @@ static int creatvol(AFPObj *obj, /* Once volumes are loaded, we never change options again, we just delete em when they're removed from afp.conf */ for (struct vol *vol = Volumes; vol; vol = vol->v_next) { - if (STRCMP(name, ==, vol->v_localname)) { + if (STRCMP(path, ==, vol->v_path)) { LOG(log_debug, logtype_afpd, "createvol('%s'): already loaded", name); vol->v_deleted = 0; + volume = vol; goto EC_CLEANUP; } } @@ -579,75 +567,77 @@ static int creatvol(AFPObj *obj, * deny -> either no list (-1), or not in list (0) */ if (pwd) { - if (accessvol(obj, getoption(obj->iniconfig, name, "deny", preset), pwd->pw_name) == 1) + if (accessvol(obj, getoption(obj->iniconfig, section, "deny", preset), pwd->pw_name) == 1) goto EC_CLEANUP; - if (accessvol(obj, getoption(obj->iniconfig, name, "allow", preset), pwd->pw_name) == 0) + if (accessvol(obj, getoption(obj->iniconfig, section, "allow", preset), pwd->pw_name) == 0) goto EC_CLEANUP; - if (hostaccessvol(obj, name, getoption(obj->iniconfig, name, "denied_hosts", preset)) == 1) + if (hostaccessvol(obj, section, getoption(obj->iniconfig, section, "denied_hosts", preset)) == 1) goto EC_CLEANUP; - if (hostaccessvol(obj, name, getoption(obj->iniconfig, name, "allowed_hosts", preset)) == 0) + if (hostaccessvol(obj, section, getoption(obj->iniconfig, section, "allowed_hosts", preset)) == 0) goto EC_CLEANUP; } EC_NULL( volume = calloc(1, sizeof(struct vol)) ); volume->v_flags = AFPVOL_USEDOTS | AFPVOL_UNIX_PRIV; + EC_NULL( volume->v_configname = strdup(section)); + #ifdef HAVE_ACLS volume->v_flags |= AFPVOL_ACLS; #endif volume->v_vfs_ea = AFPVOL_EA_AUTO; volume->v_umask = obj->options.umask; - if (val = getoption(obj->iniconfig, name, "password", preset)) + if (val = getoption(obj->iniconfig, section, "password", preset)) EC_NULL( volume->v_password = strdup(val) ); - if (val = getoption(obj->iniconfig, name, "veto", preset)) + if (val = getoption(obj->iniconfig, section, "veto", preset)) EC_NULL( volume->v_password = strdup(val) ); - if (val = getoption(obj->iniconfig, name, "volcharset", preset)) + if (val = getoption(obj->iniconfig, section, "volcharset", preset)) EC_NULL( volume->v_volcodepage = strdup(val) ); else EC_NULL( volume->v_volcodepage = strdup("UTF8") ); - if (val = getoption(obj->iniconfig, name, "maccharset", preset)) + if (val = getoption(obj->iniconfig, section, "maccharset", preset)) EC_NULL( volume->v_maccodepage = strdup(val) ); else EC_NULL( volume->v_maccodepage = strdup(obj->options.maccodepage) ); - if (val = getoption(obj->iniconfig, name, "dbpath", preset)) + if (val = getoption(obj->iniconfig, section, "dbpath", preset)) EC_NULL( volume->v_dbpath = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, name, "cnidscheme", preset)) + if (val = getoption(obj->iniconfig, section, "cnidscheme", preset)) EC_NULL( volume->v_cnidscheme = strdup(val) ); - if (val = getoption(obj->iniconfig, name, "umask", preset)) + if (val = getoption(obj->iniconfig, section, "umask", preset)) volume->v_umask = (int)strtol(val, NULL, 8); - if (val = getoption(obj->iniconfig, name, "dperm", preset)) + if (val = getoption(obj->iniconfig, section, "dperm", preset)) volume->v_dperm = (int)strtol(val, NULL, 8); - if (val = getoption(obj->iniconfig, name, "fperm", preset)) + if (val = getoption(obj->iniconfig, section, "fperm", preset)) volume->v_fperm = (int)strtol(val, NULL, 8); - if (val = getoption(obj->iniconfig, name, "perm", preset)) + if (val = getoption(obj->iniconfig, section, "perm", preset)) volume->v_perm = (int)strtol(val, NULL, 8); - if (val = getoption(obj->iniconfig, name, "volsizelimit", preset)) + if (val = getoption(obj->iniconfig, section, "volsizelimit", preset)) volume->v_limitsize = (uint32_t)strtoul(val, NULL, 10); - if (val = getoption(obj->iniconfig, name, "preexec", preset)) + if (val = getoption(obj->iniconfig, section, "preexec", preset)) EC_NULL( volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, name, "postexec", preset)) + if (val = getoption(obj->iniconfig, section, "postexec", preset)) EC_NULL( volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, name, "root_preexec", preset)) + if (val = getoption(obj->iniconfig, section, "root_preexec", preset)) EC_NULL( volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, name, "root_postexec", preset)) + if (val = getoption(obj->iniconfig, section, "root_postexec", preset)) EC_NULL( volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, val, pwd, path, name) ); - if (val = getoption(obj->iniconfig, name, "adouble", preset)) { + if (val = getoption(obj->iniconfig, section, "adouble", preset)) { if (strcmp(val, "v2") == 0) volume->v_adouble = AD_VERSION2; else if (strcmp(val, "ea") == 0) @@ -656,7 +646,7 @@ static int creatvol(AFPObj *obj, volume->v_adouble = AD_VERSION; } - if (val = getoption(obj->iniconfig, name, "cnidserver", preset)) { + if (val = getoption(obj->iniconfig, section, "cnidserver", preset)) { EC_NULL( p = strdup(val) ); volume->v_cnidserver = p; if (q = strrchr(val, ':')) { @@ -668,7 +658,7 @@ static int creatvol(AFPObj *obj, } - if (val = getoption(obj->iniconfig, name, "ea", preset)) { + if (val = getoption(obj->iniconfig, section, "ea", preset)) { if (strcasecmp(val, "ad") == 0) volume->v_vfs_ea = AFPVOL_EA_AD; else if (strcasecmp(val, "sys") == 0) @@ -677,7 +667,7 @@ static int creatvol(AFPObj *obj, volume->v_vfs_ea = AFPVOL_EA_NONE; } - if (val = getoption(obj->iniconfig, name, "casefold", preset)) { + if (val = getoption(obj->iniconfig, section, "casefold", preset)) { if (strcasecmp(val, "tolower") == 0) volume->v_casefold = AFPVOL_UMLOWER; else if (strcasecmp(val, "toupper") == 0) @@ -688,7 +678,7 @@ static int creatvol(AFPObj *obj, volume->v_casefold = AFPVOL_ULOWERMUPPER; } - if (val = getoption(obj->iniconfig, name, "options", preset)) { + if (val = getoption(obj->iniconfig, section, "options", preset)) { q = strdup(val); if (p = strtok(q, ", ")) { while (p) { @@ -737,8 +727,8 @@ static int creatvol(AFPObj *obj, * 3) rwlist exists -> ro unless user is in it. */ if (pwd) { - if (accessvol(obj, getoption(obj->iniconfig, name, "rolist", preset), pwd->pw_name) == 1 - || accessvol(obj, getoption(obj->iniconfig, name, "rwlist", preset), pwd->pw_name) == 0) + if (accessvol(obj, getoption(obj->iniconfig, section, "rolist", preset), pwd->pw_name) == 1 + || accessvol(obj, getoption(obj->iniconfig, section, "rwlist", preset), pwd->pw_name) == 0) volume->v_flags |= AFPVOL_RO; } @@ -775,6 +765,7 @@ static int creatvol(AFPObj *obj, /* because v_vid has not been decided yet. */ suffixlen = sprintf(suffix, "#%X", lastvid + 1 ); + vlen = strlen( name ); /* Unicode Volume Name */ @@ -891,14 +882,15 @@ static int creatvol(AFPObj *obj, volume->v_obj = obj; EC_CLEANUP: + LOG(log_debug, logtype_afpd, "createvol: END: %d", ret); if (ret != 0) { if (volume) { volume_free(volume); free(volume); } + return NULL; } - LOG(log_debug, logtype_afpd, "createvol: END: %d", ret); - EC_EXIT; + return volume; } /* ---------------------- @@ -934,7 +926,9 @@ static int readvolfile(AFPObj *obj, const struct passwd *pwent) char volname[AFPVOL_U8MNAMELEN + 1]; char tmp[MAXPATHLEN + 1]; const char *preset, *default_preset, *p; + char *q, *u; int i; + struct passwd *pw; LOG(log_debug, logtype_afpd, "readvolfile: BEGIN"); @@ -942,8 +936,7 @@ static int readvolfile(AFPObj *obj, const struct passwd *pwent) LOG(log_debug, logtype_afpd, "readvolfile: sections: %d", secnum); const char *secname; - if ((p = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "vol preset", NULL))) { - default_preset = p; + if ((default_preset = iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "vol preset", NULL))) { LOG(log_debug, logtype_afpd, "readvolfile: default_preset: %s", default_preset); } @@ -952,25 +945,44 @@ static int readvolfile(AFPObj *obj, const struct passwd *pwent) if (!vol_section(secname)) continue; + if (STRCMP(secname, ==, INISEC_HOMES)) { + have_uservol = 1; + if (obj->username[0] == 0) + /* not an AFP session, but cnid daemon, dbd or ad util */ + continue; + if ((p = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "basedir", NULL)) == NULL) + continue; + strlcpy(tmp, p, MAXPATHLEN); + strlcat(tmp, "/", MAXPATHLEN); + strlcat(tmp, obj->username, MAXPATHLEN); + strlcat(tmp, "/", MAXPATHLEN); + if (p = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "path", NULL)) + strlcat(tmp, p, MAXPATHLEN); + } else { + /* Get path */ + if ((p = iniparser_getstring(obj->iniconfig, secname, "path", NULL)) == NULL) + continue; + strlcpy(tmp, p, MAXPATHLEN); + } - /* Get path */ - if ((p = iniparser_getstring(obj->iniconfig, secname, "path", NULL)) == NULL) - continue; - strlcpy(tmp, p, MAXPATHLEN); if (volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL) == NULL) continue; - strlcpy(tmp, secname, AFPVOL_U8MNAMELEN); - LOG(log_debug, logtype_afpd, "readvolfile: volume: %s", volname); - - /* do variable substitution for volname */ - if (volxlate(obj, volname, sizeof(volname) - 1, tmp, pwent, path, NULL) == NULL) { - continue; + /* do variable substitution for volume name */ + if (STRCMP(secname, ==, INISEC_HOMES)) { + if (p = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "name", "$u's home")) + strlcpy(tmp, p, MAXPATHLEN); + else + strlcpy(tmp, p, MAXPATHLEN); + } else { + strlcpy(tmp, secname, AFPVOL_U8MNAMELEN); } + if (volxlate(obj, volname, sizeof(volname) - 1, tmp, pwent, path, NULL) == NULL) + continue; preset = iniparser_getstring(obj->iniconfig, secname, "vol preset", NULL); - creatvol(obj, pwent, path, volname, preset ? preset : default_preset ? default_preset : NULL); + creatvol(obj, pwent, secname, volname, path, preset ? preset : default_preset ? default_preset : NULL); } EC_CLEANUP: @@ -1075,8 +1087,12 @@ int load_volumes(AFPObj *obj, void (*delvol_fn)(struct vol *)) if (Volumes) { if (!volfile_changed(&obj->options)) goto EC_CLEANUP; - for (vol = Volumes; vol; vol = vol->v_next) + have_uservol = 0; + for (vol = Volumes; vol; vol = vol->v_next) { + if (vol->v_flags & AFPVOL_UNIX_CTXT) + continue; vol->v_deleted = 1; + } } else { LOG(log_debug, logtype_afpd, "load_volumes: no volumes yet"); EC_ZERO_LOG( lstat(obj->options.configfile, &st) ); @@ -1163,13 +1179,109 @@ struct vol *getvolbyvid(const uint16_t vid ) return( vol ); } -struct vol *getvolbypath(const char *path) +struct vol *getvolbypath(AFPObj *obj, const char *path) { - struct vol *vol = NULL; + EC_INIT; + struct vol *vol; struct vol *tmp; + const struct passwd *pw; + char volname[AFPVOL_U8MNAMELEN + 1]; + char volpath[MAXPATHLEN + 1]; + char tmpbuf[MAXPATHLEN + 1]; + const char *secname, *basedir, *p = NULL, *subpath = NULL, *subpathconfig; + char *user = NULL, *prw; + + LOG(log_debug, logtype_afpd, "getvolbypath(\"%s\")", path); for (tmp = Volumes; tmp; tmp = tmp->v_next) { if (strncmp(path, tmp->v_path, strlen(tmp->v_path)) == 0) { + vol = tmp; + goto EC_CLEANUP; + } + } + + /* might be a user home, check for that and create a volume if yes */ + if (!have_uservol) + EC_FAIL; + + int secnum = iniparser_getnsec(obj->iniconfig); + + for (int i = 0; i < secnum; i++) { + secname = iniparser_getsecname(obj->iniconfig, i); + if (STRCMP(secname, ==, INISEC_HOMES)) + break; + } + + if (STRCMP(secname, !=, INISEC_HOMES)) + EC_FAIL; + + EC_NULL_LOG( basedir = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "basedir", NULL) ); + + LOG(log_debug, logtype_afpd, "getvolbypath: user home section: '%s', basedir: '%s'", secname, basedir); + + if (strncmp(path, basedir, strlen(basedir)) != 0) + EC_FAIL; + + strlcpy(tmpbuf, basedir, MAXPATHLEN); + strlcat(tmpbuf, "/", MAXPATHLEN); + + p = path + strlen(basedir); + while (*p == '/') + p++; + EC_NULL_LOG( user = strdup(p) ); + + if (prw = strchr(user, '/')) + *prw++ = 0; + if (prw != 0) + subpath = prw; + + strlcat(tmpbuf, user, MAXPATHLEN); + strlcat(tmpbuf, "/", MAXPATHLEN); + + 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; + + EC_NULL( pw = getpwnam(user) ); + + LOG(log_debug, logtype_afpd, "getvolbypath(\"%s\"): user: %s, homedir: %s => volpath: \"%s\"", + path, user, pw->pw_dir, volpath); + + /* do variable substitution for volume name */ + p = iniparser_getstring(obj->iniconfig, INISEC_HOMES, "name", "$u's home"); + strlcpy(tmpbuf, p, AFPVOL_U8MNAMELEN); + EC_NULL_LOG( volxlate(obj, volname, sizeof(volname) - 1, tmpbuf, pw, volpath, 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); + +EC_CLEANUP: + endpwent(); + if (user) + free(user); + if (ret != 0) + vol = NULL; + return vol; +} + +struct vol *getvolbyname(const char *name) +{ + struct vol *vol = NULL; + struct vol *tmp; + + for (tmp = Volumes; tmp; tmp = tmp->v_next) { + if (strncmp(name, tmp->v_configname, strlen(tmp->v_configname)) == 0) { vol = tmp; break; } -- 2.39.2