#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
+#include <dirent.h>
#include "gssd.h"
#include "err_util.h"
}
};
+static int
+topdirs_add_entry(struct dirent *dent)
+{
+ struct topdirs_info *tdi;
+
+ tdi = calloc(sizeof(struct topdirs_info), 1);
+ if (tdi == NULL) {
+ printerr(0, "ERROR: Couldn't allocate struct topdirs_info\n");
+ return -1;
+ }
+ tdi->dirname = malloc(PATH_MAX);
+ if (tdi->dirname == NULL) {
+ printerr(0, "ERROR: Couldn't allocate directory name\n");
+ free(tdi);
+ return -1;
+ }
+ snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name);
+ tdi->fd = open(tdi->dirname, O_RDONLY);
+ if (tdi->fd != -1) {
+ fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
+ fcntl(tdi->fd, F_NOTIFY,
+ DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+ }
+
+ TAILQ_INSERT_HEAD(&topdirs_list, tdi, list);
+ return 0;
+}
+
+static void
+topdirs_free_list(void)
+{
+ struct topdirs_info *tdi;
+
+ TAILQ_FOREACH(tdi, &topdirs_list, list) {
+ free(tdi->dirname);
+ if (tdi->fd != -1)
+ close(tdi->fd);
+ TAILQ_REMOVE(&topdirs_list, tdi, list);
+ free(tdi);
+ }
+}
+
+static int
+topdirs_init_list(void)
+{
+ DIR *pipedir;
+ struct dirent *dent;
+ int ret;
+
+ TAILQ_INIT(&topdirs_list);
+
+ pipedir = opendir(pipefs_dir);
+ if (pipedir == NULL) {
+ printerr(0, "ERROR: could not open rpc_pipefs directory '%s': "
+ "%s\n", pipefs_dir, strerror(errno));
+ return -1;
+ }
+ for (dent = readdir(pipedir); dent != NULL; dent = readdir(pipedir)) {
+ if (dent->d_type != DT_DIR ||
+ strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0) {
+ continue;
+ }
+ ret = topdirs_add_entry(dent);
+ if (ret)
+ goto out_err;
+ }
+ closedir(pipedir);
+ return 0;
+out_err:
+ topdirs_free_list();
+ return -1;
+}
+
void
gssd_run()
{
int ret;
struct sigaction dn_act;
- int fd;
sigset_t set;
/* Taken from linux/Documentation/dnotify.txt: */
sigaddset(&set, DNOTIFY_SIGNAL);
sigprocmask(SIG_UNBLOCK, &set, NULL);
- if ((fd = open(pipefs_nfsdir, O_RDONLY)) == -1) {
- printerr(0, "ERROR: failed to open %s: %s\n",
- pipefs_nfsdir, strerror(errno));
- exit(1);
- }
- fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL);
- fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+ if (topdirs_init_list() != 0)
+ return;
init_client_list();
scan_poll_results(ret);
}
}
- close(fd);
+ topdirs_free_list();
+
return;
}
* linked list of struct clnt_info which associates a clntXXX directory
* with an index into pollarray[], and other basic data about that client.
*
- * Directory structure: created by the kernel nfs client
- * {pipefs_nfsdir}/clntXX : one per rpc_clnt struct in the kernel
- * {pipefs_nfsdir}/clntXX/krb5 : read uid for which kernel wants
+ * Directory structure: created by the kernel
+ * {rpc_pipefs}/{dir}/clntXX : one per rpc_clnt struct in the kernel
+ * {rpc_pipefs}/{dir}/clntXX/krb5 : read uid for which kernel wants
* a context, write the resulting context
- * {pipefs_nfsdir}/clntXX/info : stores info such as server name
+ * {rpc_pipefs}/{dir}/clntXX/info : stores info such as server name
*
* Algorithm:
- * Poll all {pipefs_nfsdir}/clntXX/krb5 files. When ready, data read
- * is a uid; performs rpcsec_gss context initialization protocol to
+ * Poll all {rpc_pipefs}/{dir}/clntXX/krb5 files. When data is ready,
+ * read and process; performs rpcsec_gss context initialization protocol to
* get a cred for that user. Writes result to corresponding krb5 file
* in a form the kernel code will understand.
* In addition, we make sure we are notified whenever anything is
- * created or destroyed in {pipefs_nfsdir} or in an of the clntXX directories,
- * and rescan the whole {pipefs_nfsdir} when this happens.
+ * created or destroyed in {rpc_pipefs} or in any of the clntXX directories,
+ * and rescan the whole {rpc_pipefs} when this happens.
*/
struct pollfd * pollarray;
sscanf(p, "port: %127s\n", cb_port);
/* check service, program, and version */
- if(memcmp(service, "nfs", 3)) return -1;
+ if (memcmp(service, "nfs", 3) != 0)
+ return -1;
*prog = atoi(program + 1); /* skip open paren */
*vers = atoi(version);
- if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
- goto fail;
+
+ if (strlen(service) == 3 ) {
+ if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
+ (*vers != 4)))
+ goto fail;
+ } else if (memcmp(service, "nfs4_cb", 7) == 0) {
+ if (*vers != 1)
+ goto fail;
+ }
if (cb_port[0] != '\0') {
port = atoi(cb_port);
static int
process_clnt_dir_files(struct clnt_info * clp)
{
- char kname[32];
- char sname[32];
- char info_file_name[32];
+ char name[PATH_MAX];
+ char info_file_name[PATH_MAX];
if (clp->krb5_fd == -1) {
- snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
- clp->krb5_fd = open(kname, O_RDWR);
+ snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
+ clp->krb5_fd = open(name, O_RDWR);
}
if (clp->spkm3_fd == -1) {
- snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
- clp->spkm3_fd = open(sname, O_RDWR);
+ snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
+ clp->spkm3_fd = open(name, O_RDWR);
}
- if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
+ if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
return -1;
snprintf(info_file_name, sizeof(info_file_name), "%s/info",
clp->dirname);
}
static void
-process_clnt_dir(char *dir)
+process_clnt_dir(char *dir, char *pdir)
{
struct clnt_info * clp;
if (!(clp = insert_new_clnt()))
goto fail_destroy_client;
- if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
+ /* An extra for the '/', and an extra for the null */
+ if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) {
goto fail_destroy_client;
}
- memcpy(clp->dirname, dir, strlen(dir));
+ sprintf(clp->dirname, "%s/%s", pdir, dir);
if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
printerr(0, "ERROR: can't open %s: %s\n",
clp->dirname, strerror(errno));
* directories, since the DNOTIFY could have been in there.
*/
static void
-update_old_clients(struct dirent **namelist, int size)
+update_old_clients(struct dirent **namelist, int size, char *pdir)
{
struct clnt_info *clp;
void *saveprev;
int i, stillhere;
+ char fname[PATH_MAX];
for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+ /* only compare entries in the global list that are from the
+ * same pipefs parent directory as "pdir"
+ */
+ if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue;
+
stillhere = 0;
for (i=0; i < size; i++) {
- if (!strcmp(clp->dirname, namelist[i]->d_name)) {
+ snprintf(fname, sizeof(fname), "%s/%s",
+ pdir, namelist[i]->d_name);
+ if (strcmp(clp->dirname, fname) == 0) {
stillhere = 1;
break;
}
/* Search for a client by directory name, return 1 if found, 0 otherwise */
static int
-find_client(char *dirname)
+find_client(char *dirname, char *pdir)
{
struct clnt_info *clp;
+ char fname[PATH_MAX];
- for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
- if (!strcmp(clp->dirname, dirname))
+ for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
+ snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
+ if (strcmp(clp->dirname, fname) == 0)
return 1;
+ }
return 0;
}
return -1;
}
- update_old_clients(namelist, j);
+ update_old_clients(namelist, j, pipe_name);
for (i=0; i < j; i++) {
if (i < FD_ALLOC_BLOCK
&& !strncmp(namelist[i]->d_name, "clnt", 4)
- && !find_client(namelist[i]->d_name))
- process_clnt_dir(namelist[i]->d_name);
+ && !find_client(namelist[i]->d_name, pipe_name))
+ process_clnt_dir(namelist[i]->d_name, pipe_name);
free(namelist[i]);
}
update_client_list(void)
{
int retval = -1;
+ struct topdirs_info *tdi;
- retval = process_pipedir(pipefs_nfsdir);
- if (retval)
- printerr(0, "ERROR: processing %s\n", pipefs_nfsdir);
+ TAILQ_FOREACH(tdi, &topdirs_list, list) {
+ retval = process_pipedir(tdi->dirname);
+ if (retval)
+ printerr(1, "WARNING: error processing %s\n",
+ tdi->dirname);
+ }
return retval;
}