envstore-2.0.4/Changelog0000600000175000001440000000241011326613256014025 0ustar derfusersenvstore 2.0.4 - Sat Jan 23 2010 * Preserve leading space in saved variables * Improved some error messages envstore 2.0.3 - Fri Dec 11 2009 * Fix a bug in the Makefile (the test script was still run with zsh) envstore 2.0.2 - Wed Dec 9 2009 * Rewrite test script in sh * Fix a bug when outputting parameters with empty values (envstore used to print random binary data after the value) envstore 2.0.1 - Wed Dec 2 2009 * Remove Bloat[tm] from the source * Use -mdoc macros in the manuals * Increase maximum length of parameter name/value envstore 2.0 - Mon Nov 2 2009 * Rewrite in C * Renamed envstore show to envstore list * Newlines in variable values are no longer supported * Introduces single-character arguments (envstore s == envstore save etc) envstore 1.2 - Thu Jul 9 2009 * Use Storable instead of Simplestore * Use ENVSTORE_FILE parameter to set where the store is saved envstore 1.1 - Wed Jul 1 2009 * Use Simplestore to save the environment * Various code and documentation improvements * The store file is now saved as /tmp/envstore-UID envstore 1.0 - Thu May 21 2009 * save, show, eval, remove and clear parameters * basic security checks * Umlauts, spaces etc. work fine envstore-2.0.4/Makefile0000600000175000001440000000137511326613256013664 0ustar derfusersCFLAGS = -Wall -Wextra -pedantic -O2 prefix = /usr/local all: bin/envstore bin/%: src/%.c $(CC) $(CFLAGS) -o $@ $< install: bin/envstore mkdir -p $(prefix)/bin $(prefix)/share/man/man1 cp bin/envstore $(prefix)/bin/envstore cp bin/envify $(prefix)/bin/envify cp man/1/envify $(prefix)/share/man/man1/envify.1 cp man/1/envstore $(prefix)/share/man/man1/envstore.1 chmod 755 $(prefix)/bin/envstore chmod 755 $(prefix)/bin/envify chmod 644 $(prefix)/share/man/man1/envify.1 chmod 644 $(prefix)/share/man/man1/envstore.1 uninstall: rm -f $(prefix)/bin/envstore $(prefix)/bin/envify rm -f $(prefix)/share/man/man1/envify.1 rm -f $(prefix)/share/man/man1/envstore.1 test: test/main clean: rm -f bin/envstore .PHONY: all install uninstall test clean envstore-2.0.4/README0000600000175000001440000000042311326613256013075 0ustar derfusersRequires: C Installation: As user, run make make test then, as root make install --- UPPATE NOTE --- When updating from envstore 1.x (perl) to 2.x (C), be sure to remove the old store file. Otherwise, envstore may run an infinite loop while attempting to load it. envstore-2.0.4/bin/envify0000700000175000001440000000005011326613256014205 0ustar derfusers#!/bin/sh eval $(envstore eval) exec $* envstore-2.0.4/src/envstore.c0000600000175000001440000001245711326613256015027 0ustar derfusers/* * Copyright © 2009,2010 by Daniel Friesel * License: WTFPL * * Function policy: Fail early (use err/errx if something goes wrong) */ #include #include #include #include #include #include #include #define CMD_EVAL 1 #define CMD_LIST 2 #define CMD_RM 3 #define CMD_SAVE 4 #define PARAM_LENGTH 256 #define VALUE_LENGTH 1024 #define SCAN_FORMAT "%255s%*1[ ]%1023[^\n]\n" static FILE * store_open(char *file) { struct stat finfo; uid_t self_uid = geteuid(); FILE *fp = fopen(file, "r"); /* * err() should be used here, but since envstore save may or may not have * an existing store to work with, return NULL if there's no usable store. */ if (fp == NULL) return NULL; if (fstat(fileno(fp), &finfo) != 0) err(EXIT_FAILURE, "%s: Unable to check file mode", file); if (finfo.st_uid != self_uid) errx(EXIT_FAILURE, "%s: File is insecure (must be owned by you, not uid %d)", file, finfo.st_uid); if ((finfo.st_mode & 077) > 0) errx(EXIT_FAILURE, "%s: File is insecure (should have mode 0600, not %04o)", file, finfo.st_mode & 07777); return fp; } static char * new_filename(char *file) { char *new_file = malloc(strlen(file) + 5); if (new_file == NULL) err(EXIT_FAILURE, "malloc"); if (snprintf(new_file, strlen(file) + 5, "%s.tmp", file) < 3) err(EXIT_FAILURE, "snprintf"); return new_file; } static FILE * store_open_new(char *file) { FILE *fp; umask(0077); fp = fopen(file, "w"); if (fp == NULL) err(EXIT_FAILURE, "%s: Unable to open", file); return fp; } /* * A little note on shell quoting: * ' at beginning and end do most of the job for us, except when we have a ' * inside the quoted value. It can't be escaped directly, so we end the quote * (with a ') and then add an escaped '. Possible ways are \' and "'" (in this * case, the latter is used). Afterwards another normal ' is added and the * quoted string continues. */ static inline void print_escaped(char *name, char *content) { unsigned int i; printf("export %s='", name); for (i = 0; i < strlen(content); i++) { if (content[i] == '\'') fputs("'\"'\"'", stdout); else putchar(content[i]); } fputs("'\n", stdout); } static void command_disp(char *file, int command) { char vname[PARAM_LENGTH]; char vcontent[VALUE_LENGTH]; int read_items; FILE *fp = store_open(file); if (fp == NULL) exit(EXIT_SUCCESS); while ((read_items = fscanf(fp, SCAN_FORMAT, vname, vcontent)) != EOF) { if (read_items == 0) errx(EXIT_FAILURE, "%s: Cannot read items, file corrupt?", file); if (command == CMD_LIST) printf("%-15s = %s\n", vname, vcontent); else print_escaped(vname, vcontent); vname[0] = '\0'; vcontent[0] = '\0'; } if (fclose(fp) != 0) err(EXIT_FAILURE, "%s: Unable to close", file); } static void command_rm_save(char *old_file, char *param, char *value, int argc, int mode) { char curparam[PARAM_LENGTH]; char curvalue[VALUE_LENGTH]; char *newvalue; char *new_file = new_filename(old_file); FILE *old_fp = store_open(old_file); FILE *new_fp = store_open_new(new_file); if (old_fp != NULL) { while (fscanf(old_fp, SCAN_FORMAT, curparam, curvalue) != EOF) { if (strcmp(curparam, param) != 0) if (fprintf(new_fp, "%s %s\n", curparam, curvalue) <= 0) err(EXIT_FAILURE, "%s: Unable to write (fprintf)", new_file); } if (fclose(old_fp) != 0) err(EXIT_FAILURE, "%s: Unable to close", old_file); } if (mode == CMD_SAVE) { if (argc > 3) newvalue = value; else newvalue = getenv(param); if (newvalue == NULL) errx(EXIT_FAILURE, "parameter '%s' has no value", param); if ((strlen(param) > PARAM_LENGTH - 1) || (strlen(newvalue) > VALUE_LENGTH - 1)) errx(EXIT_FAILURE, "parameter or value too long (see man envstore -> LIMITATIONS)"); if (fprintf(new_fp, "%s %s\n", param, newvalue) <= 0) err(EXIT_FAILURE, "%s: Unable to write (fprintf)", new_file); } if (fclose(new_fp) != 0) err(EXIT_FAILURE, "%s: Unable to close", new_file); if (rename(new_file, old_file) != 0) err(EXIT_FAILURE, "%s: Unable to rename to %s", new_file, old_file); } static inline void command_clear(char *store_file) { /* * No error checking - assume that the file didn't exist in the first place * if unlink fails. */ unlink(store_file); } int main(int argc, char **argv) { char *store_file; uid_t my_uid = geteuid(); if (argc < 2) errx(EXIT_FAILURE, "Insufficient arguments"); store_file = getenv("ENVSTORE_FILE"); if (store_file == NULL) { store_file = malloc(64); if (store_file == NULL) { err(EXIT_FAILURE, "malloc"); } if (snprintf(store_file, 63, "/tmp/envstore-%d", (int)my_uid) < 10) { err(EXIT_FAILURE, "snprintf"); } } switch (argv[1][0]) { case 'c': command_clear(store_file); break; case 'e': command_disp(store_file, CMD_EVAL); break; case 'l': command_disp(store_file, CMD_LIST); break; case 'r': if (argc < 3) errx(EXIT_FAILURE, "Usage: rm "); command_rm_save(store_file, argv[2], argv[3], argc, CMD_RM); break; case 's': if (argc < 3) errx(EXIT_FAILURE, "Usage: save [value]"); command_rm_save(store_file, argv[2], argv[3], argc, CMD_SAVE); break; default: errx(EXIT_FAILURE, "Unknown action: %s", argv[1]); break; } return EXIT_SUCCESS; } envstore-2.0.4/provides/zsh/completions/_envstore0000600000175000001440000000214611326613256021143 0ustar derfusers#compdef envstore ## vim:ft=zsh ## completion for envstore release-3 ## Daniel Friesel ## https://derf.homelinux.org/~derf/dotfiles/completion/_envstore ## see also: http://git.cloudconnected.org/?p=envstore.git;a=summary local -a options options_nofile options=( 'clear:forget stored parameters' 'eval:generate shell code to set parameters' 'list:list saved parameters in human-readable format' 'rm:delete saved parameter' 'save:save parameter' ) options_nofile=( 'save:save parameter' ) function _saved_param () { _wanted parameter expl 'saved parameter' \ compadd $(envstore eval | cut -d ' ' -f 2 | cut -d '=' -f 1) } if (( CURRENT == 2 )) { if [[ -r /tmp/envstore-$UID ]] { _describe command options } else { _describe command options_nofile } } elif (( CURRENT == 3 )) { case ${words[2]} in e*) _arguments -s '2::option:(-e)' ;; r*) _saved_param ;; s*) _parameters -g '(scalar|integer)*export*' ;; *) _message 'no more arguments' esac } elif [[ $CURRENT == 4 && ${words[2]} == save ]] { _message 'value' } else { _message 'no more arguments' } envstore-2.0.4/test/envify0000600000175000001440000000001311326613256014412 0ustar derfusersecho $oaei envstore-2.0.4/test/main0000700000175000001440000000612411326613256014050 0ustar derfusers#!/bin/sh -e # # Run 'test/main security' for security checks. # Note that these require root access and iteraction with the test script. if [ "$1" = security ]; then test_security=1 else test_security=0 fi store_file="/tmp/envstore-test-$$" testdir=$(mktemp -d /tmp/envstore.XXXXXX) export ENVSTORE_FILE=$store_file PATH=./bin:$PATH trap "envstore clear" INT echo "# make" make -s -B echo "# make install" make -s install prefix=$testdir echo "# make uninstall" make -s uninstall prefix=$testdir rm -r $testdir echo "# envstore clear" envstore clear echo "# envstore save var" export hello=world envstore save hello unset hello echo "# envstore eval" eval $(envstore eval) test "$hello" = world unset hello echo "# envstore rm" envstore rm hello eval $(envstore eval) test -z "$hello" echo "# envstore save var value" envstore save hello world echo "# envstore eval" eval $(envstore eval) test "$hello" = world unset hello echo "# envstore clear" envstore clear eval $(envstore eval) test -z "$hello" echo "# envstore save + eval (spaces in value), save var" export hello='your mom' envstore save hello unset hello eval $(envstore eval) test "$hello" = 'your mom' unset hello envstore clear echo "# envstore save + eval (spaces in value), save var value" envstore save hello 'your mom' eval $(envstore eval) test "$hello" = 'your mom' unset hello echo "# envstore save (leading space in value)" envstore save hello ' world' eval $(envstore eval) test "$hello" = ' world' unset hello echo "# envstore save (trailing space in value)" envstore save hello 'world ' eval $(envstore eval) test "$hello" = 'world ' unset hello echo "# envstore save (overwrite)" envstore save hello world eval $(envstore eval) test "$hello" = world envstore clear echo "# envstore save (' in value)" envstore save hello "the ' dude" eval $(envstore eval) test "$hello" = "the ' dude" unset hello echo "# envstore save (multiple 's in value)" envstore save hello "the '' ' dude ' moose" eval $(envstore eval) test "$hello" = "the '' ' dude ' moose" unset hello echo "# envstore save (UTF-8)" export hello='mÿde Rentner… und so' envstore save hello unset hello eval $(envstore eval) test "$hello" = 'mÿde Rentner… und so' unset hello envstore clear # former --extended tests echo "# invalid invocations" ! envstore save > /dev/null 2>&1 unset nonexistent ! envstore save nonexistent > /dev/null 2>&1 ! envstore rm > /dev/null 2>&1 echo "# other invocations" envstore list envstore eval envstore rm nonexistent envstore clear echo "# envify" envstore save oaei lalala test "$(bin/envify sh test/envify)" = lalala envstore clear if [ "$test_security" = 1 ]; then echo "# world-writable store file" envstore save fucked yes chmod 777 $store_file test "$(envstore eval)" != "export fucked='yes'" rm $store_file envstore save fucked yes echo "Now, enter the following as root:" echo " chown root $store_file" echo -n "[press return when done] " read wayne test "$(envstore eval)" != "export fucked='yes'" echo "Looking good, you may remove the file now" echo " rm $store_file" echo -n "[press return when done] " read wayne fi envstore-2.0.4/man/1/envify0000600000175000001440000000071611326613256014360 0ustar derfusers.Dd December 1, 2009 .Dt ENVIFY 1 .Os .Sh NAME .Nm envify .Nd execute a command in the environment saved with envstore .Sh SYNOPSIS .Nm .Ar command .Op Ar args ... .Sh DESCRIPTION .Nm loads the environment saved by .Nm envstore and then executes .Ar command . .Pp Any arguments specified afterwards will be passed to the command (as one would expect). .Sh LIMITATIONS The .Xr envstore 1 limitations for null bytes apply here as well. .Sh SEE ALSO .Xr envstore 1 envstore-2.0.4/man/1/envstore0000600000175000001440000000311211326613256014716 0ustar derfusers.Dd December 1, 2009 .Dt ENVSTORE 1 .Os .Sh NAME .Nm envstore .Nd save and restore environment variables .Sh SYNOPSIS .Nm .Ar command .Op Ar args ... .Sh DESCRIPTION .Nm can save and restore environment variables, thus transferring them between different shells. .Pp .Ar command must be one of .Bl -tag -width "rm" .It Cm clear Forget all stored variables .It Cm eval Produce shell code for evaluation, restoring all saved variables .It Cm list List saved variables in better readable format .It Cm save Ar variable Op Ar value Save .Ar variable either with its current shell value or with .Ar value .It Cm rm Ar variable Remove .Ar variable from store .El .Pp Note: Only the first character of .Ar command is checked, so .Nm .Cm e instead of .Nm .Cm eval , .Nm .Cm c for .Nm .Cm clear , etc., are also valid. .Sh ENVIRONMENT .Bl -tag -width "ENVSTORE_FILE" .It Ev ENVSTORE_FILE The file in which the environment parameters are stored, .Pa /tmp/envstore- Ns Va EUID by default, .El .Sh LIMITATIONS Variable names or values must not contain null bytes or newlines. .Pp Due to limitations imposed by most shells, it is not possible to save parameters containing more than one consecutive whitespace. .Nm will save and display them correctly, but unless you do .Ev IFS trickery, your shell will not be able to load them. .Pp The current maximum length (in bytes) is 255 bytes for the variable name and 1023 bytes for its content. .Sh AUTHOR .Nm was written by .An Daniel Friesel Aq derf@derf.homelinux.org . .Pp Original idea and script by .An Maximilian Gass Aq mxey@ghosthacking.net . .Sh SEE ALSO .Xr envify 1