From owner-svn-soc-all@FreeBSD.ORG Mon Jul 2 15:23:03 2012 Return-Path: Delivered-To: svn-soc-all@FreeBSD.org Received: from socsvn.FreeBSD.org (unknown [IPv6:2001:4f8:fff6::2f]) by hub.freebsd.org (Postfix) with SMTP id E7CD31065670 for ; Mon, 2 Jul 2012 15:23:00 +0000 (UTC) (envelope-from gpf@FreeBSD.org) Received: by socsvn.FreeBSD.org (sSMTP sendmail emulation); Mon, 02 Jul 2012 15:23:00 +0000 Date: Mon, 02 Jul 2012 15:23:00 +0000 From: gpf@FreeBSD.org To: svn-soc-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-Id: <20120702152300.E7CD31065670@hub.freebsd.org> Cc: Subject: socsvn commit: r238811 - soc2012/gpf/pefs_kmod/sbin/pefs X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 02 Jul 2012 15:23:03 -0000 Author: gpf Date: Mon Jul 2 15:23:00 2012 New Revision: 238811 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=238811 Log: - make pefs verify work for unmounted fs or fs without key - use a flags variable in all major functions due to different semantics or code that should be used according to whether fs is mounted and has a key or not. code is a little crude at some points and requires comments, more testing and handling of a few todos that can be seen in xxx comment headers. Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h soc2012/gpf/pefs_kmod/sbin/pefs/pefs_subr.c Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c ============================================================================== --- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Mon Jul 2 15:19:56 2012 (r238810) +++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Mon Jul 2 15:23:00 2012 (r238811) @@ -187,34 +187,43 @@ static int pefs_compute_symlink_checksum(struct file_header *fhp, const EVP_MD *md, - uint8_t hash_len) + uint8_t hash_len, int flags) { struct pefs_xslink_ctext xsl; EVP_MD_CTX mdctx; + char *buf; int error, i, md_len; + size_t buf_len; struct checksum *csp; TAILQ_INIT(&(fhp->checksums)); fhp->nhashes = 0; - /* feed parent directory to ioctl() */ - strlcpy(xsl.pxsl_filename, fhp->filename, sizeof(xsl.pxsl_filename)); - xsl.pxsl_namelen = strnlen(xsl.pxsl_filename, sizeof(xsl.pxsl_filename)); - - error = ioctl(fhp->pfd, PEFS_GETSLINKCTEXT, &xsl); - if (error != 0) { - pefs_warn("error retrieving symlink's ciphertext of %s", fhp->path); - return (PEFS_ERR_IO); + if ((flags & PEFS_UNMOUNTED) != 0 || (flags & PEFS_NOKEY) != 0) { + buf = fhp->target_path; + buf_len = strnlen(fhp->target_path, MAXPATHLEN + 1); + } + else { + /* feed parent directory to ioctl() */ + strlcpy(xsl.pxsl_filename, fhp->filename, sizeof(xsl.pxsl_filename)); + xsl.pxsl_namelen = strnlen(xsl.pxsl_filename, sizeof(xsl.pxsl_filename)); + + error = ioctl(fhp->pfd, PEFS_GETSLINKCTEXT, &xsl); + if (error != 0) { + pefs_warn("error retrieving symlink's ciphertext of %s", fhp->path); + return (PEFS_ERR_IO); + } + + dprintf(("read %d bytes from kernel\n\n", xsl.pxsl_slink_len)); + dprintf(("printing contents of buf:")); + for (i=0; i < (int)xsl.pxsl_slink_len; i++) dprintf(("%c", xsl.pxsl_slink[i])); + dprintf(("!\n")); + buf = xsl.pxsl_slink; + buf_len = xsl.pxsl_slink_len; } - - dprintf(("read %d bytes from kernel\n\n", xsl.pxsl_slink_len)); - dprintf(("printing contents of buf:")); - for (i=0; i < (int)xsl.pxsl_slink_len; i++) dprintf(("%c", xsl.pxsl_slink[i])); - dprintf(("!\n")); - EVP_MD_CTX_init(&mdctx); EVP_DigestInit_ex(&mdctx, md, NULL); - EVP_DigestUpdate(&mdctx, xsl.pxsl_slink, xsl.pxsl_slink_len); + EVP_DigestUpdate(&mdctx, buf, buf_len); csp = malloc(sizeof(struct checksum)); if (csp == NULL) { @@ -243,18 +252,22 @@ static int pefs_compute_file_checksums(struct file_header *fhp, const EVP_MD *md, - uint8_t hash_len) + uint8_t hash_len, int flags) { struct pefs_xsector_ctext xsct; + char sector_buf[PEFS_SECTOR_SIZE]; EVP_MD_CTX mdctx; struct stat sb; - off_t resid; + off_t offset, resid; + FILE * fp; + char *buf; uint32_t bytes_to_read; + size_t buf_len; int error, i, md_len; struct checksum *csp; if (fhp->target_path != NULL) - return (pefs_compute_symlink_checksum(fhp, md, hash_len)); + return (pefs_compute_symlink_checksum(fhp, md, hash_len, flags)); TAILQ_INIT(&(fhp->checksums)); @@ -267,34 +280,58 @@ resid = sb.st_size; if (resid == 0) { pefs_warn("empty files are not allowed: %s", fhp->path); - return (PEFS_ERR_INVALID); + return (PEFS_ERR_GENERIC); + } + + fp = NULL; + if ((flags & PEFS_UNMOUNTED) != 0 || (flags & PEFS_NOKEY) != 0) { + fp = fdopen(fhp->fd, "r"); + if (fp == NULL) { + pefs_warn("could not open file for reading: %s", fhp->path); + return (PEFS_ERR_IO); + } } fhp->nhashes = 0; + offset = 0; xsct.pxsct_offset = 0; while (resid > 0) { if (resid > PEFS_SECTOR_SIZE) bytes_to_read = PEFS_SECTOR_SIZE; else bytes_to_read = resid; - - resid-=bytes_to_read; - xsct.pxsct_ctext_len = bytes_to_read; - error = ioctl(fhp->fd, PEFS_GETSECTORCTEXT, &xsct); - if (error != 0) { - pefs_warn("error retrieving ciphertext of %s", fhp->path); - return (PEFS_ERR_IO); + + if ((flags & PEFS_UNMOUNTED) != 0 || (flags & PEFS_NOKEY) != 0) { + fread(sector_buf, bytes_to_read, sizeof(char), fp); + if (ferror(fp)) { + pefs_warn("error reading from file: %s", fhp->path); + return (PEFS_ERR_IO); + } + buf = sector_buf; + buf_len = bytes_to_read; + resid-=bytes_to_read; + } + else { + resid-=bytes_to_read; + xsct.pxsct_ctext_len = bytes_to_read; + error = ioctl(fhp->fd, PEFS_GETSECTORCTEXT, &xsct); + if (error != 0) { + pefs_warn("error retrieving ciphertext of %s", fhp->path); + return (PEFS_ERR_IO); + } + xsct.pxsct_offset+= xsct.pxsct_ctext_len; + buf = xsct.pxsct_ctext; + buf_len = xsct.pxsct_ctext_len; } - xsct.pxsct_offset+= xsct.pxsct_ctext_len; EVP_MD_CTX_init(&mdctx); EVP_DigestInit_ex(&mdctx, md, NULL); - EVP_DigestUpdate(&mdctx, xsct.pxsct_ctext, xsct.pxsct_ctext_len); + EVP_DigestUpdate(&mdctx, buf, buf_len); - dprintf(("read %d bytes from kernel\n\n", bytes_to_read)); - dprintf(("printing contents of buffer:")); - for (i=0; i < (int)bytes_to_read; i++) dprintf(("%c", xsct.pxsct_ctext[i])); - dprintf(("!\n")); + //dprintf(("read %d bytes\n\n", buf_len)); + //dprintf(("printing contents of buffer:")); + //for (i=0; i < (int)buf_len; i++) dprintf(("%c", buf[i])); + //dprintf(("!\n")); csp = malloc(sizeof(struct checksum)); if (csp == NULL) { @@ -320,6 +357,15 @@ fhp->nhashes++; } + /* + * XXXgpf: [TODO] better move the fp into file_header struct and deal with + * closing it during pefs_file_close. + */ + if (fp != NULL) { + fclose(fp); + fhp->fd = -1; + } + return (0); } @@ -333,11 +379,11 @@ } static int -pefs_allocate_hash_table(struct cuckoo_hash_table *chtp, uint32_t nelements, int flags) +pefs_allocate_hash_table(struct cuckoo_hash_table *chtp, uint32_t nelements, int alloc_flag) { uint32_t i; - if (flags == PEFS_EXTEND) { + if (alloc_flag == PEFS_EXTEND) { /* * spending 15% more space for each table lowers the chance to fall into an * infinite loop during cuckoo insertion to about 1.5%. @@ -349,12 +395,12 @@ return (PEFS_ERR_GENERIC); } } - else if (flags == PEFS_NOEXTEND) { + else if (alloc_flag == PEFS_NOEXTEND) { chtp->size = nelements; chtp->nelements = nelements; } /* reallocate the hash tables in case of infinite loop during cuckoo insert */ - else if (flags == PEFS_REALLOC) { + else if (alloc_flag == PEFS_REALLOC) { chtp->size = pefs_next_prime(chtp->size + 1); if (chtp->size < chtp->nelements) { pefs_warn("numeric overflow while computing new hash table size"); @@ -582,11 +628,40 @@ * file id used is checksum = VMAC(E(tweak || filename)) */ static int -pefs_get_file_id(struct file_header *fhp) +pefs_get_file_id(struct file_header *fhp, int flags) { struct pefs_xnamecsum xncs; uint64_t temp; - int error; + char *enc, *buf; + int error, r; + size_t buf_len, enc_len; + + if ((flags & PEFS_NOKEY) != 0 || (flags & PEFS_UNMOUNTED) != 0) { + enc = fhp->filename; + enc_len = strnlen(fhp->filename, sizeof(fhp->filename)); + enc++; + enc_len--; + buf_len = MAXNAMLEN + 1; + buf = malloc(buf_len); + if (buf == NULL) { + pefs_warn("memory allocation error"); + return (PEFS_ERR_SYS); + } + + r = pefs_name_pton(enc, enc_len, buf, buf_len); + if (r <= 0) { + pefs_warn("failed to extract file id from encrypted filename: %s", fhp->filename); + error = PEFS_ERR_GENERIC; + } + else { + memcpy(&temp, buf, sizeof(temp)); + fhp->file_id = be64toh(temp); + error = 0; + } + + free(buf); + return (error); + } strlcpy(xncs.pxnc_filename, fhp->filename, sizeof(xncs.pxnc_filename)); xncs.pxnc_namelen = strnlen(xncs.pxnc_filename, sizeof(xncs.pxnc_filename)); @@ -600,7 +675,7 @@ fhp->file_id = be64toh(temp); } else - pefs_warn("failed to fetch file id from kernel"); + pefs_warn("failed to fetch file id from kernel for filename: %s", fhp->filename); return (error); } @@ -662,7 +737,7 @@ continue; } - error = pefs_get_file_id(&targetfh); + error = pefs_get_file_id(&targetfh, 0); if (error == 0) { res = pefs_cuckoo_lookup(chtp, &targetfh); if (res == NULL) @@ -753,7 +828,7 @@ } static int -pefs_open_semantic_checks(struct file_header *fhp, struct statfs *fsp, struct hardlink_head *hlc_headp) +pefs_open_semantic_checks(struct file_header *fhp, struct statfs *fsp, struct hardlink_head *hlc_headp, int flags) { char dirbuf[MAXPATHLEN + 1], namebuf[MAXNAMLEN + 1]; char sbuf[MAXPATHLEN + 1]; @@ -840,9 +915,15 @@ * symlink. * e.g. a directory */ - if (lstat(fhp->target_path, &sb) != 0) { - warn("cannot stat symlink's target file %s", fhp->target_path); - return (PEFS_ERR_SYS); + if ((flags & PEFS_NOKEY) == 0 && (flags & PEFS_UNMOUNTED) == 0) { + /* + * If target_path is encrypted due to no key or unmounted fs, + * lstat will always fail. + */ + if (lstat(fhp->target_path, &sb) != 0) { + warn("cannot stat symlink's target file %s", fhp->target_path); + return (PEFS_ERR_SYS); + } } /* @@ -880,16 +961,18 @@ return (PEFS_ERR_INVALID); } - if (fstatfs(fhp->fd, &this_fs) == -1) { - pefs_warn("statfs failed: %s: %s", fhp->path, strerror(errno)); - return (PEFS_ERR_SYS); - } + if ((flags & PEFS_UNMOUNTED) == 0) { + if (fstatfs(fhp->fd, &this_fs) == -1) { + pefs_warn("statfs failed: %s: %s", fhp->path, strerror(errno)); + return (PEFS_ERR_SYS); + } - if ((fsp->f_fsid.val[0] != this_fs.f_fsid.val[0]) || - (fsp->f_fsid.val[1] != this_fs.f_fsid.val[1])) { - pefs_warn("filename: %s does not reside in filesystem %s", - fhp->path, fsp->f_mntonname); - return (PEFS_ERR_INVALID); + if ((fsp->f_fsid.val[0] != this_fs.f_fsid.val[0]) || + (fsp->f_fsid.val[1] != this_fs.f_fsid.val[1])) { + pefs_warn("filename: %s does not reside in filesystem %s", + fhp->path, fsp->f_mntonname); + return (PEFS_ERR_INVALID); + } } /* Keep all hardlink file headers in a rb tree */ @@ -977,19 +1060,19 @@ TAILQ_INIT(&fh_head); RB_INIT(&hlc_head); while((fhp = pefs_next_file(fpin, &error, &nfiles)) != NULL) { - error = pefs_open_semantic_checks(fhp, &fs, &hlc_head); + error = pefs_open_semantic_checks(fhp, &fs, &hlc_head, 0); if (error != 0) { pefs_close_file(fhp); return (error); } - error = pefs_get_file_id(fhp); + error = pefs_get_file_id(fhp, 0); if (error != 0) { pefs_close_file(fhp); return (error); } - error = pefs_compute_file_checksums(fhp, md, hash_len); + error = pefs_compute_file_checksums(fhp, md, hash_len, 0); if (error != 0) { pefs_close_file(fhp); return (error); @@ -1602,7 +1685,8 @@ */ static int pefs_traverse_fs(struct cuckoo_hash_table *chtp, const EVP_MD *md, uint8_t hash_len, DIR *dirp, - char *path, struct statfs *fsp, struct hardlink_head *hlc_headp, struct file_header_head *fh_headp) + char *path, struct statfs *fsp, struct hardlink_head *hlc_headp, struct file_header_head *fh_headp, + int flags) { char tmpath[MAXPATHLEN]; struct stat sb; @@ -1614,6 +1698,7 @@ while (dirp) { sdp = readdir(dirp); if (sdp != NULL) { + /* XXXgpf: Need to pay special attention to these files */ if (strcmp(sdp->d_name, "..") == 0 || strcmp(sdp->d_name, ".") == 0 || strcmp(sdp->d_name, ".pefs.db") == 0 || strcmp(sdp->d_name, ".pefs.conf") == 0 || strcmp(sdp->d_name, ".pefs.checksum") == 0) @@ -1629,7 +1714,7 @@ closedir(dirp); return (PEFS_ERR_SYS); } - error = pefs_traverse_fs(chtp, md, hash_len, dirtmp, tmpath, fsp, hlc_headp, fh_headp); + error = pefs_traverse_fs(chtp, md, hash_len, dirtmp, tmpath, fsp, hlc_headp, fh_headp, flags); if (error != 0) { closedir(dirp); return (PEFS_ERR_SYS); @@ -1652,14 +1737,15 @@ return (PEFS_ERR_SYS); } strlcpy(fhp->path, tmpath, sizeof(fhp->path)); - error = pefs_open_semantic_checks(fhp, fsp, NULL); + + error = pefs_open_semantic_checks(fhp, fsp, NULL, flags); if (error != 0) { closedir(dirp); free(fhp); return (error); } - error = pefs_get_file_id(fhp); + error = pefs_get_file_id(fhp, flags); if (error != 0) { pefs_close_file(fhp); free(fhp); @@ -1674,13 +1760,14 @@ } indexfhp->found = 1; - error = pefs_compute_file_checksums(fhp, md, hash_len); + error = pefs_compute_file_checksums(fhp, md, hash_len, flags); if (error != 0) { pefs_close_file(fhp); free(fhp); return (error); } + /* get sb for pefs_rb_insert */ error = lstat(fhp->path, &sb); if (error != 0) { warn("cannot stat file %s", fhp->path); @@ -1695,17 +1782,13 @@ free(fhp); return (error); } - + /* - * XXXgpf: there's a chance of a false positive here. - * When creating .pefs.checksum we only check if there's a file id - * collision between files that need integrity checking, not against - * the entire filesystem. So there's a possibility we will have a - * false positive in case there are 2 files with the same file id - * now that we traverse the entire fs. - * - * So should exit and treat a checksum comparison as an error? - */ + * XXXgpf: [TODO] if error encountered during + * pefs_compare_cehcksums, then store this information + * but keep on traversing the fs to find other errors + * as well. + */ error = pefs_compare_checksums(fhp, indexfhp, hash_len); //if (error != 0) { //pefs_close_file(fhp); @@ -1730,6 +1813,7 @@ return (PEFS_ERR_SYS); } +/* XXXgpf: probably turn this to int */ static void pefs_found_all_entries(struct cuckoo_hash_table *chtp) { @@ -1757,7 +1841,7 @@ * XXXgpf: [TODO] comments */ int -pefs_verify_checksum(int fdin, char *fsroot) +pefs_verify_checksum(int fdin, char *fsroot, int flags) { struct statfs fs; struct checksum_file_header cfh; @@ -1797,25 +1881,27 @@ //pefs_print_hash_tables(&cht, hash_len); + RB_INIT(&hlc_head); + TAILQ_INIT(&fh_head); + dirp = opendir(fsroot); if (dirp == NULL) { pefs_warn("failed to open dir %s", fsroot); return (PEFS_ERR_SYS); } - RB_INIT(&hlc_head); - TAILQ_INIT(&fh_head); - - error = pefs_traverse_fs(&cht, md, hash_len, dirp, fsroot, &fs, &hlc_head, &fh_head); + error = pefs_traverse_fs(&cht, md, hash_len, dirp, fsroot, &fs, &hlc_head, &fh_head, flags); if (error != 0) return (error); //pefs_rb_print(&hlc_head); pefs_rb_warn(&hlc_head); - pefs_symlink_warn(&cht, &fh_head); + if ((flags & PEFS_UNMOUNTED) == 0 && (flags & PEFS_NOKEY) == 0) + pefs_symlink_warn(&cht, &fh_head); pefs_found_all_entries(&cht); /* XXXgpf: [TODO] free mem in the end and when error occurs */ + /* XXXgpf: [TODO] verify action should also use a signature to verify .pefs.checksum */ return (0); } Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c ============================================================================== --- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c Mon Jul 2 15:19:56 2012 (r238810) +++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c Mon Jul 2 15:23:00 2012 (r238811) @@ -1102,7 +1102,7 @@ /* * XXXgpf: Instead of a man page entry: * - * pefs verify checksumpath filesystem + * pefs verify [-u/-n] checksumpath filesystem * * $command ... * @@ -1112,12 +1112,27 @@ static int pefs_verify(int argc, char *argv[]) { + struct stat sb; char fsroot[MAXPATHLEN]; - int error, fdin, i; + int error, fdin, flags, i; - while ((i = getopt(argc, argv, "a:i:p:")) != -1) + flags = 0; + while ((i = getopt(argc, argv, "nu")) != -1) switch(i) { - /* XXXgpf: Should I add an option to tell if it's a mounted or unmounted fs ? */ + case 'n': + flags|= PEFS_NOKEY; + if ((flags & PEFS_UNMOUNTED) != 0) { + pefs_warn("flags -u and -n are mutually exclusive"); + return (PEFS_ERR_INVALID); + } + break; + case 'u': + flags|= PEFS_UNMOUNTED; + if ((flags & PEFS_NOKEY) != 0) { + pefs_warn("flags -u and -n are mutually exclusive"); + return (PEFS_ERR_INVALID); + } + break; default: pefs_usage(); } @@ -1140,15 +1155,28 @@ argc -=1; argv +=1; - /* XXXgpf: For now, assume that verify works only with a mounted pefs fs */ - initfsroot(argc, argv, 0, fsroot, sizeof(fsroot)); + if ((flags & PEFS_UNMOUNTED) == 0) + initfsroot(argc, argv, 0, fsroot, sizeof(fsroot)); + else { + strlcpy(fsroot, argv[0], sizeof(fsroot)); + if (stat(fsroot, &sb) != 0) { + warn("cannot stat fs root: %s", fsroot); + return (PEFS_ERR_NOENT); + } - error = pefs_verify_checksum(fdin, fsroot); + if (S_ISDIR(sb.st_mode) == 0) { + pefs_warn("fs root is not a directory: %s", fsroot); + return (PEFS_ERR_SYS); + } + } + + error = pefs_verify_checksum(fdin, fsroot, flags); if (error == 0) printf("everything's ok!\n"); close(fdin); return (error); + } static void @@ -1177,7 +1205,7 @@ " pefs showchains [-fp] [-i iterations] [-k keyfile] filesystem\n" " pefs showalgs\n" " pefs addchecksum [-a algo] [-i inputfile] [-p checksumpath] filesystem\n" -" pefs verify [checksumpath filesystem]\n" +" pefs verify [-n/u] [checksumpath filesystem]\n" ); exit(PEFS_ERR_USAGE); } Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h ============================================================================== --- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h Mon Jul 2 15:19:56 2012 (r238810) +++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h Mon Jul 2 15:23:00 2012 (r238811) @@ -44,6 +44,9 @@ #define PEFS_FILE_KEYCONF ".pefs.conf" #define PEFS_FILE_CHECKSUM ".pefs.checksum" +#define PEFS_NOKEY 0x0001 +#define PEFS_UNMOUNTED 0x0002 + #define PEFS_KEYCONF_ALG_IND 0 #define PEFS_KEYCONF_ITERATIONS_IND 1 @@ -95,7 +98,9 @@ const struct pefs_xkey *xk_parent); uintmax_t pefs_keyid_as_int(char *keyid); int pefs_create_checksum_file(FILE *fpin, char *fsroot, char *csm_path, const char *algo); -int pefs_verify_checksum(int fdin, char *fsroot); +int pefs_verify_checksum(int fdin, char *fsroot, int flags); + +int pefs_name_pton(char const *src, size_t srclen, u_char *target, size_t targsize); const char * pefs_alg_name(struct pefs_xkey *xk); void pefs_alg_list(FILE *stream); Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_subr.c ============================================================================== --- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_subr.c Mon Jul 2 15:19:56 2012 (r238810) +++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_subr.c Mon Jul 2 15:23:00 2012 (r238811) @@ -74,3 +74,72 @@ return (0); } +#define Assert(Cond) (void)0 + +/* + * Algorithm is standard base64 with few exceptions: + * - file system friendly alphabet + * - no paddings and whitespace skip + */ +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_"; +int +pefs_name_pton(char const *src, size_t srclen, u_char *target, size_t targsize) +{ + int tarindex, state, ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0' && srclen-- > 0) { + if (target && (size_t)tarindex >= targsize) + return (-1); + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + target[tarindex] |= (pos - Base64) >> 4; + if ((size_t)tarindex + 1 < targsize) + target[tarindex+1] = + ((pos - Base64) & 0x0f) << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + target[tarindex] |= (pos - Base64) >> 2; + if ((size_t)tarindex + 1 < targsize) + target[tarindex+1] = + ((pos - Base64) & 0x03) << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + default: + return (-1); + } + } + + if (tarindex == 0) + return (-1); + return (tarindex); +}