| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- /** BEGIN COPYRIGHT BLOCK
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #if defined( _WIN32 )
- #include <sys/stat.h> /* for S_IREAD and S_IWRITE */
- #include <windows.h>
- #include <time.h>
- #include "proto-ntutil.h"
- #else
- #include <sys/socket.h>
- #include <sys/errno.h>
- #include <sys/param.h>
- #include <sys/types.h>
- #if defined(LINUX) /* I bet other Unix would like
- * this flag. But don't want to
- * break other builds so far */
- #include <unistd.h>
- #endif
- #endif
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include "ldap.h"
- #include "../slapi-plugin.h"
- #include "../slap.h"
- #include <nspr.h>
- #include <nss.h>
- #include "../../plugins/pwdstorage/pwdstorage.h"
- int ldap_syslog;
- int ldap_syslog_level;
- int slapd_ldap_debug = LDAP_DEBUG_ANY;
- #ifdef _WIN32
- int *module_ldap_debug;
- #endif
- int detached;
- FILE *error_logfp;
- FILE *access_logfp;
- struct pw_scheme *pwdhashscheme;
- int heflag = 0;
- static int slapd_config(const char *configdir, const char *configfile);
- static int entry_has_attr_and_value(Slapi_Entry *e, const char *attrname, char *value);
- static void
- usage( name )
- char *name;
- {
- fprintf( stderr, "usage: %s -D config-dir [-H] [-s scheme | -c comparepwd ] password...\n", name );
- exit( 1 );
- }
- /*
- * If global "heflag" is non-zero, un-hex-encode the string
- * and return a decoded copy. Otherwise return a copy of the
- * string.
- */
- static char *
- decode( char *orig )
- {
- char *r;
- if ( NULL == orig ) {
- return NULL;
- }
- r = slapi_ch_calloc( 1, strlen( orig ) + 2 );
- strcpy( r, orig );
- if ( heflag ) {
- char *s;
- for ( s = r; *s != '\0'; ++s ) {
- if ( *s == '%' && ldap_utf8isxdigit( s+1 ) && ldap_utf8isxdigit( s+2 )) {
- memmove( s, s + 1, 2 );
- s[ 2 ] = '\0';
- *s = strtoul( s, NULL, 16 );
- memmove( s + 1, s + 3, strlen( s + 3 ) + 1 );
- }
- }
- }
- return r;
- }
- static slapdFrontendConfig_t *
- init_config(char *configdir)
- {
- char *abs_configdir = NULL;
- char *configfile = NULL;
- char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
- slapdFrontendConfig_t *slapdFrontendConfig = NULL;
- if (configdir == NULL) { /* use default */
- configdir = TEMPLATEDIR;
- configfile = "template-dse.ldif";
- }
- /* kexcoff: quite the same as slapd_bootstrap_config */
- FrontendConfig_init();
- abs_configdir = rel2abspath( configdir );
- if ( config_set_configdir( "configdir (-D)", abs_configdir,
- errorbuf, 1) != LDAP_SUCCESS ) {
- fprintf( stderr, "%s\n", errorbuf );
- return( NULL );
- }
- slapi_ch_free_string(&abs_configdir);
- slapdFrontendConfig = getFrontendConfig();
- if (0 == slapd_config(slapdFrontendConfig->configdir, configfile)) {
- fprintf(stderr,
- "The configuration files in directory %s could not be read or were not found. Please refer to the error log or output for more information.\n",
- slapdFrontendConfig->configdir);
- return(NULL);
- }
- return slapdFrontendConfig;
- }
- int
- main( argc, argv )
- int argc;
- char *argv[];
- {
- int i, rc;
- char *enc, *cmp, *name;
- struct pw_scheme *pwsp, *cmppwsp;
- extern int optind;
- char *cpwd = NULL; /* candidate password for comparison */
- slapdFrontendConfig_t *slapdFrontendConfig = NULL;
- char *opts = "Hs:c:D:";
- name = argv[ 0 ];
- pwsp = cmppwsp = NULL;
- #ifdef _WIN32
- module_ldap_debug = &slapd_ldap_debug;
- libldap_init_debug_level(&slapd_ldap_debug);
- #endif
- PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0 );
-
- /* Initialize NSS to make ds_salted_sha1_pw_enc() work */
- if (NSS_NoDB_Init(NULL) != SECSuccess) {
- fprintf( stderr, "Fatal error: unable to initialize the NSS subcomponent." );
- return( 1 );
- }
-
- while (( i = getopt( argc, argv, opts )) != EOF ) {
- switch ( i ) {
- case 'D':
- if (slapdFrontendConfig) {
- fprintf(stderr, "The -D configdir argument must be given only once, and must be the first argument given\n");
- usage(name);
- return 1;
- }
- if (!(slapdFrontendConfig = init_config(optarg))) {
- return(1);
- }
- break;
- case 's': /* set hash scheme */
- if (!slapdFrontendConfig) {
- if (!(slapdFrontendConfig = init_config(NULL))) {
- usage( name );
- return(1);
- }
- }
- if (( pwsp = pw_name2scheme( optarg )) == NULL ) {
- fprintf( stderr, "%s: unknown hash scheme \"%s\"\n", name,
- optarg );
- return( 1 );
- }
- break;
- case 'c': /* compare encoded password to password */
- if (!slapdFrontendConfig) {
- if (!(slapdFrontendConfig = init_config(NULL))) {
- usage( name );
- return(1);
- }
- }
- cpwd = optarg;
- break;
- case 'H': /* password(s) is(are) hex-encoded */
- if (!slapdFrontendConfig) {
- if (!(slapdFrontendConfig = init_config(NULL))) {
- usage( name );
- return(1);
- }
- }
- heflag = 1;
- break;
- default:
- usage( name );
- }
- }
- if (!slapdFrontendConfig) {
- if (!(slapdFrontendConfig = init_config(NULL))) {
- usage( name );
- return(1);
- }
- }
- if ( cpwd != NULL ) {
- cmppwsp = pw_val2scheme( decode( cpwd ), &cmp, 1 );
- }
-
- if ( cmppwsp != NULL && pwsp != NULL ) {
- fprintf( stderr, "%s: do not use -s with -c\n", name );
- usage( name );
- }
- if ( cmppwsp == NULL && pwsp == NULL ) {
- pwsp = pw_name2scheme( SALTED_SHA1_SCHEME_NAME );
- }
- if ( argc <= optind ) {
- usage( name );
- }
- if ( cmppwsp == NULL && pwsp->pws_enc == NULL ) {
- fprintf( stderr,
- "The scheme \"%s\" does not support password encoding.\n",
- pwsp->pws_name );
- return( 1 );
- }
- srand((int)time(NULL)); /* schemes such as crypt use random salt */
- for ( rc = 0; optind < argc && rc == 0; ++optind ) {
- if ( cmppwsp == NULL ) { /* encode passwords */
- if (( enc = (*pwsp->pws_enc)( decode( argv[ optind ] ))) == NULL ) {
- perror( name );
- return( 1 );
- }
- puts( enc );
- slapi_ch_free_string( &enc );
- } else { /* compare passwords */
- if (( rc = (*(cmppwsp->pws_cmp))( decode( argv[ optind ]), cmp )) == 0 ) {
- printf( "%s: password ok.\n", name );
- } else {
- printf( "%s: password does not match.\n", name );
- }
- }
- }
- return( rc == 0 ? 0 : 1 );
- }
- /* -------------------------------------------------------------- */
- /*
- kexcoff: quite similar to slapd_bootstrap_config() from the server,
- but it only loads password storage scheme plugins
- */
- static int
- slapd_config(const char *configdir, const char *givenconfigfile)
- {
- char configfile[MAXPATHLEN+1];
- PRFileInfo prfinfo;
- int rc = 0; /* Fail */
- int done = 0;
- PRInt32 nr = 0;
- PRFileDesc *prfd = 0;
- char *buf = 0;
- char *lastp = 0;
- char *entrystr = 0;
- if (!givenconfigfile) {
- givenconfigfile = CONFIG_FILENAME;
- }
- PR_snprintf(configfile, sizeof(configfile), "%s/%s", configdir, givenconfigfile);
- if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS )
- {
- fprintf(stderr,
- "The given config file %s could not be accessed, error %d\n",
- configfile, rc);
- exit( 1 );
- }
- else if (( prfd = PR_Open( configfile, PR_RDONLY,
- SLAPD_DEFAULT_FILE_MODE )) == NULL )
- {
- fprintf(stderr,
- "The given config file %s could not be read\n",
- configfile);
- exit( 1 );
- }
- else
- {
- /* read the entire file into core */
- buf = slapi_ch_malloc( prfinfo.size + 1 );
- if (( nr = slapi_read_buffer( prfd, buf, prfinfo.size )) < 0 )
- {
- fprintf(stderr,
- "Could only read %d of %d bytes from config file %s\n",
- nr, prfinfo.size, configfile);
- exit( 1 );
- }
-
- (void)PR_Close(prfd);
- buf[ nr ] = '\0';
- if(!done)
- {
- /* Convert LDIF to entry structures */
- Slapi_DN plug_dn;
- slapi_sdn_init_dn_byref(&plug_dn, PLUGIN_BASE_DN);
- while ((entrystr = dse_read_next_entry(buf, &lastp)) != NULL)
- {
- /*
- * XXXmcs: it would be better to also pass
- * SLAPI_STR2ENTRY_REMOVEDUPVALS in the flags, but
- * duplicate value checking requires that the syntax
- * and schema subsystems be initialized... and they
- * are not yet.
- */
- Slapi_Entry *e = slapi_str2entry(entrystr,
- SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF);
- if (e == NULL)
- {
- fprintf(stderr,
- "The entry [%s] in the configfile %s was empty or could not be parsed\n",
- entrystr, configfile);
- continue;
- }
- /* see if the entry is a child of the plugin base dn */
- if (slapi_sdn_isgrandparent(&plug_dn,
- slapi_entry_get_sdn_const(e)))
- {
- if ( entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "pwdstoragescheme"))
- {
- /* add the syntax/matching/pwd storage scheme rule plugin */
- if (plugin_setup(e, 0, 0, 1))
- {
- fprintf(stderr,
- "The plugin entry [%s] in the configfile %s was invalid\n",
- slapi_entry_get_dn(e), configfile);
- exit(1); /* yes this sucks, but who knows what else would go on if I did the right thing */
- }
- else
- {
- e = 0; /* successful plugin_setup consumes entry */
- }
- }
- }
- if (e)
- slapi_entry_free(e);
- }
- /* kexcoff: initialize rootpwstoragescheme and pw_storagescheme
- * if not explicilty set in the config file
- */
- config_set_storagescheme();
- slapi_sdn_done(&plug_dn);
- rc= 1; /* OK */
- }
- slapi_ch_free_string(&buf);
- }
- return rc;
- }
- /*
- kexcoff: direclty copied fron the server code
- See if the given entry has an attribute with the given name and the
- given value; if value is NULL, just test for the presence of the given
- attribute; if value is an empty string (i.e. value[0] == 0),
- the first value in the attribute will be copied into the given buffer
- and returned
- */
- static int
- entry_has_attr_and_value(Slapi_Entry *e, const char *attrname,
- char *value)
- {
- int retval = 0;
- Slapi_Attr *attr = 0;
- if (!e || !attrname)
- return retval;
- /* see if the entry has the specified attribute name */
- if (!slapi_entry_attr_find(e, attrname, &attr) && attr)
- {
- /* if value is not null, see if the attribute has that
- value */
- if (!value)
- {
- retval = 1;
- }
- else
- {
- Slapi_Value *v = 0;
- int index = 0;
- for (index = slapi_attr_first_value(attr, &v);
- v && (index != -1);
- index = slapi_attr_next_value(attr, index, &v))
- {
- const char *s = slapi_value_get_string(v);
- if (!s)
- continue;
- if (!*value)
- {
- strcpy(value, s);
- retval = 1;
- break;
- }
- else if (!strcasecmp(s, value))
- {
- retval = 1;
- break;
- }
- }
- }
- }
- return retval;
- }
|