/** \file vpop.c \brief function to get domain directory of vpopmail virtual domain */ #include #include #include #include #include #include #include #include #include "vpop.h" #include "sstring.h" #include "cdb.h" /* * The function vget_dir is a modified copy of vget_assign from vpopmail. It gets the domain directory out of * the /var/qmail/users/cdb file. All the unneeded code (buffering, rewrite the domain name, uid, gid) is ripped out, * the ugly snprintf stuff is gone, the result of malloc() is checked and the code is much prettier (at least IMHO, * but that's the only one that counts here *g*). */ /** * Query the users/cdb file for information about this domain * * @param domain the domain to query * @param domaindir if not NULL the directory of this domain is stored here * @param realdomain if not NULL name of the real domain is stored here * @returns negative error code or flag if domain was found * @retval 0 domain is not in database * @retval 1 domain was found * * Function will return 1 on success, memory for domaindir will be malloced. * The directory name will always end with a single '/'. If the domain does not exist 0 is returned, -1 on error; */ int vget_dir(const char *domain, string *domaindir, char **realdomain) { int fd; int i = 0; char *cdb_key; size_t cdbkeylen; const char *cdb_buf; char *cdb_mmap = NULL; int err; struct stat st; size_t len; cdbkeylen = strlen(domain) + 2; cdb_key = malloc(cdbkeylen + 1); if (!cdb_key) return -ENOMEM; cdb_key[0] = '!'; memcpy(cdb_key + 1, domain, cdbkeylen - 2); cdb_key[cdbkeylen - 1] = '-'; cdb_key[cdbkeylen] = '\0'; /* try to open the cdb file */ fd = open("users/cdb", O_RDONLY); if (fd < 0) { err = -errno; free(cdb_key); return err; } if (fstat(fd, &st) < 0) { err = -errno; while ((close(fd) < 0) && (errno == EINTR)); free(cdb_key); return err; } if (!st.st_size) { err = 0; while (close(fd) < 0) { if (errno != EINTR) err = -errno; } free(cdb_key); return err; } /* search the cdb file for our requested domain */ cdb_buf = cdb_seekmm(fd, cdb_key, cdbkeylen, &cdb_mmap, &st); if (cdb_buf == NULL) { free(cdb_key); return errno ? -errno : 0; } /* format of cdb_buf is : * realdomain\0uid\0gid\0path\0 */ len = strlen(cdb_buf); if (realdomain) { *realdomain = malloc(len + 1); if (!*realdomain) { munmap(cdb_mmap, st.st_size); free(cdb_key); return -ENOMEM; } memcpy(*realdomain, cdb_buf, len + 1); } cdb_buf += len + 1; /* advance pointer past the realdomain */ while( *cdb_buf++ != '\0' ); /* skip over the uid */ while( *cdb_buf++ != '\0' ); /* skip over the gid */ /* get the domain directory */ if (domaindir) { len = strlen(cdb_buf); while (*(cdb_buf + len - 1) == '/') --len; i = newstr(domaindir, len + 2); if (i != 0) { munmap(cdb_mmap, st.st_size); free(cdb_key); if (realdomain != NULL) free(realdomain); return -ENOMEM; } memcpy(domaindir->s, cdb_buf, len); domaindir->s[len] = '/'; domaindir->s[--domaindir->len] = '\0'; } err = errno; munmap(cdb_mmap, st.st_size); free(cdb_key); errno = err; return 1; }