diff options
Diffstat (limited to 'base/native-tools/src/setpin')
-rw-r--r-- | base/native-tools/src/setpin/CMakeLists.txt | 43 | ||||
-rw-r--r-- | base/native-tools/src/setpin/b64.c | 102 | ||||
-rw-r--r-- | base/native-tools/src/setpin/options.c | 184 | ||||
-rw-r--r-- | base/native-tools/src/setpin/options.h | 83 | ||||
-rw-r--r-- | base/native-tools/src/setpin/setpin.c | 1237 | ||||
-rw-r--r-- | base/native-tools/src/setpin/setpin.conf | 83 | ||||
-rw-r--r-- | base/native-tools/src/setpin/setpin_options.c | 290 | ||||
-rw-r--r-- | base/native-tools/src/setpin/setpin_options.h | 56 |
8 files changed, 2078 insertions, 0 deletions
diff --git a/base/native-tools/src/setpin/CMakeLists.txt b/base/native-tools/src/setpin/CMakeLists.txt new file mode 100644 index 000000000..b32e12b22 --- /dev/null +++ b/base/native-tools/src/setpin/CMakeLists.txt @@ -0,0 +1,43 @@ +project(setpin C) + +find_package(Ldap REQUIRED) + +set(SETPIN_PRIVATE_INCLUDE_DIRS + ${CMAKE_BINARY_DIR} + ${NSPR_INCLUDE_DIRS} + ${NSS_INCLUDE_DIRS} + ${LDAP_INCLUDE_DIRS} +) + +set(SETPIN_LINK_LIBRARIES + ${NSPR_LIBRARIES} + ${NSS_LIBRARIES} + ${LDAP_LIBRARIES} +) + +set(setpin_SRCS + b64.c + options.c + setpin.c + setpin_options.c +) + +include_directories(${SETPIN_PRIVATE_INCLUDE_DIRS}) + +add_executable(setpin ${setpin_SRCS}) + +target_link_libraries(setpin ${SETPIN_LINK_LIBRARIES}) + +install( + TARGETS setpin + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) + +install( + FILES + setpin.conf + DESTINATION + ${SHARE_INSTALL_PREFIX}/pki/native-tools/ +) diff --git a/base/native-tools/src/setpin/b64.c b/base/native-tools/src/setpin/b64.c new file mode 100644 index 000000000..1c20f3792 --- /dev/null +++ b/base/native-tools/src/setpin/b64.c @@ -0,0 +1,102 @@ +/* --- 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + + + + + + +static char nib2b64[0x40f] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + + +static int +ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen, int lenused, int wraplen ) +{ + unsigned char *byte, *stop; + unsigned char buf[3]; + char *out; + unsigned long bits; + int i, pad, len; + + len = 0; + out = dst; + stop = src + srclen; + + /* convert to base 64 (3 bytes => 4 base 64 digits) */ + for ( byte = src; byte < stop - 2; byte += 3 ) { + bits = (byte[0] & 0xff) << 16; + bits |= (byte[1] & 0xff) << 8; + bits |= (byte[2] & 0xff); + + for ( i = 0; i < 4; i++, bits <<= 6 ) { + if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) { + *out++ = '\n'; + *out++ = ' '; + lenused = 2; + } + + /* get b64 digit from high order 6 bits */ + *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; + } + } + /* add padding if necessary */ + if ( byte < stop ) { + for ( i = 0; byte + i < stop; i++ ) { + buf[i] = byte[i]; + } + for ( pad = 0; i < 3; i++, pad++ ) { + buf[i] = '\0'; + } + byte = buf; + bits = (byte[0] & 0xff) << 16; + bits |= (byte[1] & 0xff) << 8; + bits |= (byte[2] & 0xff); + + for ( i = 0; i < 4; i++, bits <<= 6 ) { + if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) { + *out++ = '\n'; + *out++ = ' '; + lenused = 2; + } + + if (( i == 3 && pad > 0 ) || ( i == 2 && pad == 2 )) { + /* Pad as appropriate */ + *out++ = '='; + } else { + /* get b64 digit from low order 6 bits */ + *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ]; + } + } + } + + *out = '\0'; + + return( out - dst ); +} + + +int +ldif_base64_encode( unsigned char *src, char *dst, int srclen, int lenused ) +{ + return ldif_base64_encode_internal( src, dst, srclen, lenused, 200); +} + diff --git a/base/native-tools/src/setpin/options.c b/base/native-tools/src/setpin/options.c new file mode 100644 index 000000000..9e2dab129 --- /dev/null +++ b/base/native-tools/src/setpin/options.c @@ -0,0 +1,184 @@ +/* --- 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + + +#include "options.h" + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +/* + * (C) 1998 Netscape Communications Corporation + * All rights reserved + * Intellectual property rulez! + * + */ + + + +/* this file maintains a static linked list of the + options it knows about +*/ + +static OPTION *option_list = NULL; +static OPTION *last_option = NULL; + +static char* OPT_parseArgument(char *arg,char**valid); + + +/* OPT_getValue(char *option, char** output) + + returns 1 if the specified option exists, + - value is put into 'output' + returns 0 if the specified option doesn't exist + - output is unchanged + +*/ + + +int OPT_getValue(char *option, char **output) { + OPTION *opt = option_list; + + while (opt) { + if (! strcmp(opt->name,option)) { + *output = opt->value; + return 1; + } + opt = opt->next; + } + return 0; +} + + +static char* OPT_parseOptFile(char *filename, char*validlist[]) +{ + FILE *fp; + char buffer[1024]; + + if (filename == NULL || filename[0] == '\0') { + return ("Bad syntax for 'optfile'\n"); + } + fp = fopen(filename,"r"); + if (fp == NULL) { + return ("Options file could not be opened for reading\n"); + } + while (fgets(buffer,1024,fp)) { + if (buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0'; + if (buffer[strlen(buffer)-1] == '\r') buffer[strlen(buffer)-1] = '\0'; + + OPT_parseArgument(strdup(buffer),validlist); + } + fclose(fp); + return NULL; +} + + + +static char *OPT_parseArgument(char *arg, char* validlist[]) { + char *error; + char *INV_ARG = "invalid argument: %s"; + char *eq; + + OPTION *new_opt; + + if (!strncmp(arg,"optfile=",8)) { + return OPT_parseOptFile(&arg[8],validlist); + } + + new_opt = (OPTION*)malloc(sizeof(OPTION)); + + new_opt->next = NULL; + new_opt->name = strdup(arg); + eq = strchr(new_opt->name,'='); + if (eq) { + *eq = 0; + } + new_opt->value = strchr(arg,'='); + + + if (new_opt->value != NULL) { + new_opt->value++; + } + + if (option_list == NULL) { + option_list = new_opt; + last_option = new_opt; + } + else { + last_option->next = new_opt; + last_option= new_opt; + } + if (!validlist) { + return NULL; + } + else { + int i=0; + while (validlist[i]) { + if (! strcmp(validlist[i],new_opt->name)) { + return NULL; + } + i+=2; + } + } + + error = (char *)malloc(strlen(INV_ARG)+strlen(new_opt->name)+5); + sprintf(error,INV_ARG,new_opt->name); + + return error; +} + + + + +/* char *OPT_parseOptions(int ac, char **av) + + constructs the linked list of options + ac: number of arguments + av: array of arguments + valid: array of valid arguments (can be null) + + returns: + NULL if no error + char* with error text if error. caller is responsible for + freeing this memory + +*/ + +char * OPT_parseOptions(int ac, char **av, char *valid[]) { + int i=0; + char *r=NULL; + + assert(option_list == NULL); + assert(last_option == NULL); + assert(av != NULL); + + if (ac == 1) return NULL; + + for (i=0; i<ac-1; i++) { + r = OPT_parseArgument(av[1+i],valid); + if (r) return r; + } + return r; +} + + + + diff --git a/base/native-tools/src/setpin/options.h b/base/native-tools/src/setpin/options.h new file mode 100644 index 000000000..80ccae478 --- /dev/null +++ b/base/native-tools/src/setpin/options.h @@ -0,0 +1,83 @@ +/* --- 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + + +#ifndef OPT_INCLUDE_H +#define OPT_INCLUDE_H + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include <config.h> +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +struct option { + struct option *next; + char *name; + char *value; +}; + +typedef struct option OPTION; + +/* OPT_getValue(char *option, char** output) + + returns 1 if the specified option exists, + - value is put into 'output' + returns 0 if the specified option doesn't exist + - output is unchanged + + 'value' will be everything after the '=' + If no '=' is present in the argument, 'output' will be + set to null. + If '=' is present, but no value is given (e.g. "file="), + output will be a pointer to a string of zero length. + +*/ + +extern int OPT_getValue(char *option, char **output); + +/* void OPT_parseOptions(int ac, char **av) + + initializes the global store with the options supplied + in av (typically used for parsing arguments passed on the + command line. Arguments are of the form 'arg=value'. + valid: array of valid arguments (can be null) + + returns: + NULL if no error + char* with error text if error. caller is responsible for + freeing this memory + + + +*/ + +extern char * OPT_parseOptions(int ac, char **av, char**valid); + +#endif diff --git a/base/native-tools/src/setpin/setpin.c b/base/native-tools/src/setpin/setpin.c new file mode 100644 index 000000000..f1bf6a8c7 --- /dev/null +++ b/base/native-tools/src/setpin/setpin.c @@ -0,0 +1,1237 @@ +/* --- 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + +/* Set-pin tool */ + + +/* This will modify the specified attribute in the directory + You must add the pin objectclass to the schema + e.g in config/slapd.oc.conf + + attribute pin bin + objectclass pinPerson + superior organizationalPerson + allows + pin +*/ + +/* + History: + version 1.2 - upgraded to NSS 3.3.1 + */ + +#define SETPIN_VERSION "1.2" + +#include "options.h" +#include "setpin_options.h" +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include <ldap.h> + +#define USE_NSS_RANDOM + +#ifdef USE_NSS_RANDOM +/* removed #include <secrng.h> as of NSS 3.9 */ +/* removed from nss3_3_1 secrngt.h*/ +typedef struct RNGContextStr RNGContext; +#endif + +#include <sechash.h> + +#include <plhash.h> +#include <prerror.h> +#include <ctype.h> + +#include <secoidt.h> +#include <nss.h> + +extern int equals(char *s, char *t); +extern SECStatus PK11_HashBuf(SECOidTag hashAlg, + unsigned char *out, + unsigned char *in, + int32 len); +extern SECStatus PK11_GenerateRandom(unsigned char *data, + int len); + +/* use NSS's new generic hash api */ +#define USE_NSS_GEN_HASH + +void exitError(char *errstring); +void exitLDAPError(char *errstring); +void doLDAPBind(); +void doLDAPSearch(LDAPMessage **result); +void doLDAPUnbind(); +void processSearchResults(LDAPMessage *r); +char *newPassword(); +void initrandom(); +void testpingen(); +void do_setup(); + + +char *sha1_pw_enc( char *pwd ); + +int errcode=0; + +LDAP *ld=NULL; +char *programName = NULL; + +FILE *output; +FILE *input; + + +PLHashTable *pinHashTable=NULL; + +#ifdef USE_NSS_RANDOM +RNGContext *rngc = NULL; +#endif + +/* this tool should really be changed to use NSPR */ +#ifdef _WIN32 +#define strcasecmp stricmp +#endif + +void exitError(char *errstring) { + char *errbuf; + + errbuf = malloc(strlen(errstring)+strlen(programName)+10); + + sprintf(errbuf,"%s error : %s\n",programName,errstring); + fputs(errbuf,stderr); + exit(errcode); +} + + +void exitLDAPError(char *errstring) { + char *ldaperr; + char *newerror; + int err; + + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + ldaperr = ldap_err2string(err); + newerror = (char*) malloc((errstring?strlen(errstring):0) + (ldaperr?strlen(ldaperr):0) +5); + sprintf(newerror,"%s (%s)",errstring?errstring:"",ldaperr?ldaperr:""); + exitError(newerror); +} + + +/* This returns an allocated string, like strdup does, except that + the duplicate string begins with the first non-whitespace character */ + +char * trim_strdup(char *s) +{ + while (*s == ' ' || *s == '\t') { + s++; + } + if (*s == '\0') return NULL; + return strdup(s); +} + +void readInputFile() { + int more_to_read=1; + char *thedn = NULL; + char *thepin = NULL; + int linenum=0; + + pinHashTable = PL_NewHashTable(256, + PL_HashString, + PL_CompareStrings, + PL_CompareValues, + NULL, /* allocOps */ + NULL); + if (pinHashTable == NULL) { + errcode=9; + exitError("Couldn't create dn->pin hashtable"); + } + + if (o_input) { + + do { + char line[4096]; + char *n; + char *checkdn; + + do { + n = fgets(line,4096,input); + linenum++; + if (! n) { + more_to_read = 0; + break; + } + + /* replace newline with null byte */ + + line[strlen(line)-1] = 0; + + if (! strncmp("dn:",line,3)) { + thedn = trim_strdup(&line[3]); + if (thedn == NULL) { + fprintf(stderr,"warning: empty line not allowed at line: %d\n",linenum); + } + } + + if (! strncmp("pin:",line,4)) { + thepin = trim_strdup(&line[4]); + } + + } while (strlen(line)); + + /* first check to see if that dn is already in the hashtable */ + + if (thepin == NULL) { + thepin = strdup(""); + } + + if (thedn && thepin) { + + checkdn = (char*) PL_HashTableLookup(pinHashTable, thedn); + if (checkdn) { + char msg[256]; + errcode = 10; + strcpy(msg,"Duplicate entry in input file for dn="); + strcat(msg,thedn); + exitError(msg); + } + + PL_HashTableAdd(pinHashTable, + thedn, + thepin); + fprintf(stderr, "Reading dn/pin ( %s, %s )\n", thedn, thepin); + if (o_debug) { + fprintf(stderr, "Reading dn/pin ( %s, %s )\n", thedn, thepin); + } + + } else { + if (o_debug) { + fprintf(stderr," ...ignoring\n"); + } + } + if (thedn != NULL) { + free(thedn); + thedn = NULL; + } + if (thepin != NULL) { + free(thepin); + thepin = NULL; + } + } while (more_to_read); + } +} + + +int main(int ac, char **av) { + char *error; + LDAPMessage *search_results; + + programName = av[0]; + if (strlen(av[0]) == 0) { + strcpy(programName, "setpin"); + } + else { + strcpy(programName, av[0]); + } + + if (ac == 1) { + int i=0; + fprintf(stderr,"Setpin utility. Version " SETPIN_VERSION "\n" + "(C) 2005 Fedora Project.\n\n"); + fprintf(stderr,"To set up directory for pin usage, modify setpin.conf, " + "then run:\n %s optfile=<svr_root>/bin/cert/tools/setpin.conf\n", programName); + fprintf(stderr,"\nUsage: %s option=value ... option=value\n\n", programName); + + for (i = 0; i < valid_args_len; i += 2) { + if (valid_args[i]) { + fprintf(stderr,"%13s : %s\n",valid_args[i],valid_args[i+1]); + } else { + errcode=0; + fprintf(stderr,"\n"); + exit(errcode); + } + } + } + + error = OPT_parseOptions(ac, av, valid_args); + if (error) { + errcode=7; + exitError(error); + } + + setDefaultOptions(); + + getOptions(); + fprintf(stderr,"\n"); + if (o_debug) { + fprintf(stderr,"about to validateOptions\n"); + } + + validateOptions(); + + /* Initialize random number generator */ + initrandom(); + + if (o_debug) { + fprintf(stderr,"about to doLDAPBind\n"); + } + + if (! o_testpingen) { + doLDAPBind(); + } + + if (o_setup) { + do_setup(); + } + + if (o_output) { + output = fopen(o_output,"w"); + if (!output) { + errcode=5; + exitError("Couldn't open output file"); + } + } else { + output = stdout; + } + + if (o_testpingen) { + testpingen(); + exit(0); + } + + if (o_input) { + input = fopen(o_input,"r"); + if (!input) { + errcode=8; + exitError("Couldn't open input file"); + } + } + + readInputFile(); + + if (o_debug) { + fprintf(stderr,"about to doLDAPSearch\n"); + } + + doLDAPSearch(&search_results); + + if (o_debug) { + fprintf(stderr,"about to processSearchResults\n"); + } + + processSearchResults(search_results); + + if (output != stdout) { + fclose(output); + } + + return 0; +} + + + +/* This function implements the 'setup' procedure, invoked when the user + specified 'setup' as one of the arguments. The point is that in this + mode, schema modifications are performed to add these things to the + directory schema: + if (schemachange argument is specified) + - 'pin' attribute as specified by the 'attribute' argument (default 'pin') + - 'pinPerson' objectclass as specified by the 'objectclass argument (dfl: pinperson) + if ('pinmanager' argument specified) + - pin manager user, with permission to remove the pin for the basedn specified + +*/ + +void do_setup() { + int i; + + char *x_values[]={NULL,NULL,NULL}; + char *a1_values[]={NULL,NULL}; + char *a2_values[]={NULL,NULL}; + char *a3_values[]={NULL,NULL}; + char *a4_values[]={NULL,NULL}; + LDAPMod x,a1,a2,a3,a4; + LDAPMod *mods[10]; + char* password=NULL; + int err; + + x_values[0] = malloc(1024); + + doLDAPBind(); + + if (o_schemachange) { + sprintf(x_values[0],"( %s-oid NAME '%s' DESC 'User Defined Attribute' SYNTAX '1.3.6.1.4.1.1466.115.121.1.5' SINGLE-VALUE )", + o_attribute, + o_attribute); + + fprintf(stderr,"Adding attribute: %s\n",x_values[0]); + x_values[1] = NULL; + x.mod_op = LDAP_MOD_ADD; + x.mod_type = "attributetypes"; + x.mod_values = x_values; + mods[0] = &x; + mods[1] = NULL; + + i = ldap_modify_ext_s(ld, "cn=schema", mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + if (err != LDAP_TYPE_OR_VALUE_EXISTS) { + exitLDAPError("couldn't modify schema when creating pin attribute"); + } else { + fprintf(stderr," .. successful\n\n"); + } + } + + sprintf(x_values[0],"( %s-oid NAME '%s' DESC 'User Defined ObjectClass' SUP 'top' MUST ( objectclass ) MAY ( aci $ %s )", + o_objectclass,o_objectclass, + o_attribute); + + fprintf(stderr,"Adding objectclass: %s\n",x_values[0]); + + x_values[1] = NULL; + x.mod_op = LDAP_MOD_ADD; + x.mod_type = "objectclasses"; + x.mod_values = x_values; + mods[0] = &x; + mods[1] = NULL; + + + i = ldap_modify_ext_s(ld, "cn=schema", mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + if (err != LDAP_TYPE_OR_VALUE_EXISTS) { + exitLDAPError("couldn't modify schema when creating objectclass"); + } else { + fprintf(stderr," .. successful\n\n"); + } + } + } + + if (o_pinmanager) { + + if (o_pinmanagerpwd == NULL) { + exitError("missing pinmanagerpwd argument"); + } + if (o_basedn == NULL) { + exitError("missing basedn argument"); + } + + password = sha1_pw_enc( o_pinmanagerpwd ); + + fprintf(stderr,"Adding user: %s\n",o_pinmanager); + + a1_values[0] = "pinmanager"; + a1_values[1] = NULL; + a1.mod_op = 0; + a1.mod_type = "sn"; + a1.mod_values = a1_values; + + a2_values[0] = "pinmanager"; + a2_values[1] = NULL; + a2.mod_op = 0; + a2.mod_type = "cn"; + a2.mod_values = a2_values; + + a3_values[0] = password; + a3_values[1] = NULL; + a3.mod_op = 0; + a3.mod_type = "userPassword"; + a3.mod_values = a3_values; + + a4_values[0] = "person"; + a4_values[1] = NULL; + a4.mod_op = 0; + a4.mod_type = "objectclass"; + a4.mod_values = a4_values; + + mods[0] = &a1; + mods[1] = &a2; + mods[2] = &a3; + mods[3] = &a4; + mods[4] = NULL; + + + i = ldap_add_ext_s(ld, o_pinmanager, mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + if (!( err == LDAP_TYPE_OR_VALUE_EXISTS || err == LDAP_ALREADY_EXISTS)) { + exitLDAPError("couldn't create new user"); + } else { + fprintf(stderr," .. successful\n\n"); + } + } + + + /* modify aci on basedn to allow pinmanager to modify pin attr */ + + fprintf(stderr,"modifying ACI for: %s\n",o_basedn); + + sprintf(x_values[0],"(target=\"ldap:///%s\")" + "(targetattr=\"pin\")" + "(version 3.0; acl \"Pin attribute\"; " + "allow (all) userdn = \"ldap:///%s\"; " + "deny(proxy,selfwrite,compare,add,write,delete,search) " + "userdn = \"ldap:///self\"; ) ", + o_basedn, + o_pinmanager); + + x_values[1] = malloc(1024); + + sprintf(x_values[1],"(target=\"ldap:///%s\")" + "(targetattr=\"objectclass\")" + "(version 3.0; acl \"Pin Objectclass\"; " + "allow (all) userdn = \"ldap:///%s\"; " + " ) ", + o_basedn, + o_pinmanager); + + x_values[2] = NULL; + x.mod_op = LDAP_MOD_ADD; + x.mod_type = "aci"; + x.mod_values = x_values; + + mods[0] = &x; + mods[1] = NULL; + + i = ldap_modify_ext_s(ld, o_basedn, mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); + if (!( err == LDAP_TYPE_OR_VALUE_EXISTS || err == LDAP_ALREADY_EXISTS)) { + exitLDAPError("couldn't modify aci on basedn"); + } else { + fprintf(stderr," .. successful\n\n"); + } + } + } + exit(0); +} + +int ldif_base64_encode( + unsigned char *src, char *dst, int srclen, int lenused ); + +/* do password hashing */ + +/* + * Number of bytes each hash algorithm produces + */ +#define SHA1_LENGTH 20 + + +char * +sha1_pw_enc( char *pwd ) +{ + unsigned char hash[ SHA1_LENGTH ]; + char *enc; + + /* SHA1 hash the user's key */ + PK11_HashBuf(SEC_OID_SHA1,hash,pwd,strlen(pwd)); + enc = malloc(256); + + sprintf( enc, "{SHA}"); + + (void)ldif_base64_encode( hash, enc + 5, + SHA1_LENGTH, -1 ); + + return( enc ); +} + +/* check the first 8 characters to see if this is a string */ + +int isstring(char *s) { + int i=0; + + for (i=0;i<8;i++) { + if (*s == 0) return 1; + if (! isprint(*s)) return 0; + s++; + } + return 1; +} + + +void doLDAPBind() { + char errbuf[1024]; + char ldapuri[1024]; + int port=389; + int r; + int status; + + if (o_port == NULL) { + if (o_ssl) { + port = 636; + /* fprintf(stderr,"o_ssl = %0x, o_certdb = %0x, o_nickname= %0x\n",o_ssl,o_certdb,o_nickname); */ + } else { + port = 389; + } + } else { + port = atoi(o_port); + } + + if (o_debug) { + fprintf(stderr,"# connecting to %s:%d\n",o_host,port); + } + + if (o_ssl) { + printf("SSL not currently supported.\n"); + exit(0); + /* ld = ldapssl_init(o_host,port,LDAPSSL_AUTH_CNCHECK); */ + } else { + snprintf(ldapuri, 1024, "ldap://%s:%i", o_host, port); + status = ldap_initialize(&ld, ldapuri); + } + + if ((status != LDAP_SUCCESS) || (ld == NULL)) { + errcode=4; + exitError("could not connect to directory server"); + } + + if (o_debug) { + fprintf(stderr,"# ldap_init completed\n"); + } + + struct berval credential; + credential.bv_val = o_bindpw; + credential.bv_len= strlen(o_bindpw); + + r = ldap_sasl_bind_s(ld, o_binddn, LDAP_SASL_SIMPLE, &credential, NULL, NULL, NULL); + if (r != LDAP_SUCCESS) { + sprintf(errbuf,"could not bind to %s:%d as %s",o_host,port,o_binddn); + if (strstr(o_binddn,"=") == NULL) { + strcat(errbuf,". Perhaps you missed the 'CN=' part of the bin DN?"); + } + exitLDAPError(errbuf); + } + + if (o_debug) { + fprintf(stderr,"# ldap_simple_bind_s completed\n"); + } +} + + +void doLDAPSearch(LDAPMessage **result ) { + int r; + char errbuf[1024]; + + r = ldap_search_ext_s( ld, o_basedn, LDAP_SCOPE_SUBTREE, + o_filter, NULL, 0, NULL, NULL, NULL, 0, result ); + + if (r != LDAP_SUCCESS ) { + sprintf(errbuf,"could not complete search with that filter. Check filter and basedn"); + exitLDAPError(errbuf); + } + + if (o_debug) { + fprintf(stderr,"# ldap_search_s completed\n"); + } +} + +void doLDAPUnbind(){ + ldap_unbind_ext_s(ld, NULL, NULL); +} + + +void processSearchResults(LDAPMessage *r) { + LDAPMessage *e; + char *dn; + char *a; + struct berval **vals; +#ifdef USE_NSS_GEN_HASH + /* HASHContext *hcx; + HASH_HashType ht; */ +#else +#endif + int i; + BerElement *ber; + char *objectclass_values[]={NULL,NULL}; + int change=0; + int pin_objectclass_exists=0; + LDAPMod objectclass, pinattribute; + LDAPMod *mods[3]; + SECStatus status = SECFailure; + + char *saltval; + int action; + char *hashbuf_source = NULL; + char hashbuf_dest[256]; + char errbuf[1024]; + int pindatasize= 0; + char *pindata = NULL; + char *generatedPassword = NULL; + struct berval *bvals[2]; + struct berval bval; + + bvals[0] = &bval; + bvals[1] = NULL; + + /* Check whether any results were found. */ + i = ldap_count_entries( ld, r ); + + fprintf(stderr,"filter %s found %d matching results.\n", o_filter,i); + + /* for each entry print out name + all attrs and values */ + for ( e = ldap_first_entry( ld, r ); e != NULL; + e = ldap_next_entry( ld, e ) ) { + + generatedPassword = NULL; + + if ( (dn = ldap_get_dn( ld, e )) != NULL ) { + fprintf(stderr, "Processing: %s\n", dn ); + if (o_input) { + generatedPassword = (char*) PL_HashTableLookup(pinHashTable,dn); + if (generatedPassword) { + fprintf(stderr, " found user from input file\n"); + } + if (! generatedPassword) { + fprintf(stderr, " Skipping (not in input file)\n"); + continue; + } + } + } + + + /* what we do here is go through all the entries looking for + 'objectclass'. + */ + + pin_objectclass_exists = 0; + change = 0; + +#define ACTION_NONE 0 +#define ACTION_REPLACE 1 +#define ACTION_ADD 2 + + action = ACTION_ADD; + + saltval = NULL; + /* loop through the entries */ + for ( a = ldap_first_attribute( ld, e, &ber ); + a != NULL; a = ldap_next_attribute( ld, e, ber ) ) { + + if ((vals = ldap_get_values_len( ld, e, a)) != NULL ) { + + if (o_debug && (! strcasecmp(o_debug,"attrs"))) { + for ( i = 0; vals[i] != NULL; i++ ) { + char *bin; + bin = "<binary>"; + if (isstring(vals[i]->bv_val)) { + bin = vals[i]->bv_val; + } + + fprintf(stderr, " %s: %s\n",a,bin); + } + } + + if (o_debug) { + fprintf(stderr," examining attribute: %s\n",a); + for ( i = 0; vals[i] != NULL; i++ ) { + fprintf(stderr," val[%d]: %s\n",i,vals[i]->bv_val); + } + } + + if (o_saltattribute != NULL) { + if (!strcasecmp(a,o_saltattribute)) { + saltval = vals[0]->bv_val; + if (o_debug) { + fprintf(stderr," setting salt value to: %s\n",saltval); + } + } + } + + if (!strcasecmp(a,"objectclass")) { + /* check if we have a pin objectclass already */ + /* Cycle through all the values for this + entry, looking for the one which matches the + objectclass we specified */ + + /* if user specified objectclass= on the commandline, + without any value, then the objectclass is assumed to + exist already */ + if (strlen(o_objectclass) == 0) { + if (o_debug) { fprintf(stderr, " user objectclass assumed to already exist\n"); } + pin_objectclass_exists=1; + } else { + for ( i = 0; vals[i] != NULL; i++ ) { + if (o_debug) { + fprintf(stderr, " checking vals[%d]=%s == objectclass=%s -> %d \n", + i,vals[i]->bv_val, o_objectclass, strcasecmp(vals[i]->bv_val,o_objectclass)); + } + if (!strcasecmp(vals[i]->bv_val,o_objectclass)) { + if (o_debug) { + fprintf(stderr, " %s: %s found\n", a, vals[i]->bv_val ); + } + pin_objectclass_exists = 1; + } + } + } + } else if (!strcasecmp(a,o_attribute)) { + if (o_clobber) { + action = ACTION_REPLACE; + } else { + action = ACTION_NONE; + } + } + + /* use ldap_value_free_len */ + ldap_value_free_len( vals ); + } + ldap_memfree( a ); + } + + if (o_debug) { fprintf(stderr, " Did the objectclass exist? %d\n", pin_objectclass_exists); } + + /* add the objectclass attribute if it doesn't already exist */ + + if (! pin_objectclass_exists) { + if (o_debug) { + fprintf(stderr,"objectclass: %s doesn't exist, adding\n",o_objectclass); + } + objectclass_values[0] = o_objectclass; + objectclass_values[1] = NULL; + objectclass.mod_op = LDAP_MOD_ADD; + objectclass.mod_type = "objectclass"; + objectclass.mod_values = objectclass_values; + mods[0] = &objectclass; + mods[1] = NULL; + + if (o_write) { + i = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + exitLDAPError("couldn't modify attribute"); + } + } + } + + pinattribute.mod_type = o_attribute; + + /* password could have been set from input file. If not, set it now */ + if (generatedPassword == NULL || (strlen(generatedPassword) == 0)) { + generatedPassword = newPassword(); + } + if (generatedPassword == NULL || (strlen(generatedPassword) == 0)) { + errcode=13; + exitError("Couldn't generate password."); + } + + /* should we hash the password? */ + if (o_hash) { + + /* we hash the DN of the user and the PIN together */ + + if (o_debug) { + fprintf(stderr,"checking salt attribute...\n"); + } + if (saltval == NULL) { + if (o_saltattribute != NULL) { + errcode = 11; + exitError("specified salt attribute not found for this user"); + } + if (o_debug) { + fprintf(stderr,"setting salt attribute to dn...\n"); + } + saltval = dn; + } + + hashbuf_source = + malloc(strlen(saltval) + strlen(generatedPassword) + 10); + if (hashbuf_source == NULL) { + errcode=12; + exitError("Couldn't allocate 'hashbuf_source'."); + } + strcpy(hashbuf_source,saltval); + strcat(hashbuf_source,generatedPassword); + + if (o_debug) { + fprintf(stderr,"hashing this: %s\n",hashbuf_source); + } + + saltval = NULL; + + /* We leave one byte at the beginning of the hash + buffer, to support the hash type */ + +#define SENTINEL_SHA1 0 +#define SENTINEL_MD5 1 +#define SENTINEL_NONE '-' + + if ((!strcmp(o_hash,"SHA1")) || (!strcmp(o_hash,"sha1")) ) { + status = PK11_HashBuf(SEC_OID_SHA1, + (unsigned char *)hashbuf_dest+1, + (unsigned char *)hashbuf_source, + strlen(hashbuf_source) + ); + hashbuf_dest[0] = SENTINEL_SHA1; + pindatasize = SHA1_LENGTH + 1; + } else if ((!strcmp(o_hash,"MD5")) || (!strcmp(o_hash,"md5")) ) { + status = PK11_HashBuf(SEC_OID_MD5, + (unsigned char *)hashbuf_dest+1, + (unsigned char *)hashbuf_source, + strlen(hashbuf_source) + ); + hashbuf_dest[0] = SENTINEL_MD5; + pindatasize = MD5_LENGTH + 1; + } else if ((!strcmp(o_hash,"NONE")) || (!strcmp(o_hash,"none")) ) { + hashbuf_dest[0] = SENTINEL_NONE; + status = SECSuccess; + memcpy(hashbuf_dest+1, + hashbuf_source, + strlen(hashbuf_source) + ); + } else { + sprintf(errbuf,"Unsupported hash type '%s'. Must be one of 'sha1', 'md5' or 'none",o_hash); + errcode = 7; + exitError(errbuf); + } + + if (status != SECSuccess) { + sprintf(errbuf,"Error hashing pin (%d)",PR_GetError()); + errcode = 9; + exitError(errbuf); + } + + pindata = hashbuf_dest; + + if (hashbuf_source != NULL) { + free(hashbuf_source); + hashbuf_source = NULL; + } + } else { + pindata = generatedPassword; + pindatasize = strlen(generatedPassword); + } + + bval.bv_len = pindatasize; + bval.bv_val = pindata; + + fprintf(stderr," Adding new %s\n",o_attribute); + + if (! o_write) { + fprintf(stderr, " [NOTE: 'write' was not specified, so no changes will be made to the directory]\n"); + } + + pinattribute.mod_bvalues = bvals; + if (action == ACTION_REPLACE) { + pinattribute.mod_op = LDAP_MOD_REPLACE|LDAP_MOD_BVALUES; + if (o_debug) { + fprintf(stderr," %s exists, replacing\n",o_attribute); + } + } else if (action == ACTION_ADD) { + if (o_debug) { + fprintf(stderr," %s doesn't exist, adding\n",o_attribute); + } + pinattribute.mod_op = LDAP_MOD_ADD|LDAP_MOD_BVALUES; + } else if (action == ACTION_NONE) { + if (o_debug) { + fprintf(stderr," %s exists. not replacing\n",o_attribute); + } + goto skip_write; + } + mods[0] = &pinattribute; + mods[1] = NULL; + + if (o_write) { + i = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); + + if (i != LDAP_SUCCESS) { + exitLDAPError("couldn't modify attribute"); + } + } + + skip_write: + + fprintf(output,"dn:%s\n",dn); + fprintf(output,"%s:%s\n",o_attribute,generatedPassword); + if (o_debug) { + fprintf(stderr,"o_write = %0x\n",(unsigned int)o_write); + } + if (! o_write) { + fprintf(output,"status:notwritten\n"); + } else { + if (action == ACTION_NONE) { + fprintf(output,"status:notreplaced\n"); + } else { + if (i != LDAP_SUCCESS) { + fprintf(output,"status:writefailed\n"); + } else { + if (action == ACTION_ADD) { + fprintf(output,"status:added\n"); + } else if (action == ACTION_REPLACE) { + fprintf(output,"status:replaced\n"); + } + } + } + } + + fprintf(output,"\n"); + + if (dn) { + ldap_memfree( dn ); + dn = NULL; + } + + if ( ber != NULL ) { + ber_free( ber, 0 ); + } + fprintf(stderr, "\n" ); + } + ldap_msgfree( r ); +} + + +/* this function uses i_minlength and i_maxlength to determine the + size of the password to generate */ + +static char *UCalpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +static char *LCalpha = "abcdefghijklmnopqrstuvwxyz"; +static char *numbers = "0123456789"; +static char *punc = "!#$%&*+,-./:;<=>?@[]^{|}"; + +static char *charpool = NULL; /* carpool, geddit? */ +static int charpoolsize; + +static char *RNG_ALPHA = "RNG-alpha"; +static char *RNG_PRINTABLEASCII = "RNG-printableascii"; +static char *RNG_ALPHANUM = "RNG-alphanum"; + + +/* build the pool of characters we can use for the password */ + +void buildCharpool() { + char err_buf[1024]; + charpool = (char*) malloc(256); + + charpool[0] = '\0'; + + if ( o_case == NULL) { + strcat(charpool,LCalpha); /* then add the lowercase */ + } else { + if (strcmp(o_case,"upperonly")) { + errcode = 7; + exitError("Illegal value for case="); + } + } + + + if ( !strcmp(o_gen,RNG_ALPHA) || + !strcmp(o_gen,RNG_ALPHANUM) || + !strcmp(o_gen,RNG_PRINTABLEASCII) ) { + strcat(charpool,UCalpha); /* add uppercase chars */ + } else { + sprintf(err_buf,"invalid value '%s' for gen= option",o_gen); + errcode = 7; + exitError(err_buf); + } + + if ( strcmp(o_gen,"RNG-alpha")) { /* not alpha-only */ + strcat(charpool,numbers); + } + if (! strcmp(o_gen,"RNG-printableascii")) { + strcat(charpool, punc); + } + if (o_debug) { + fprintf(stderr,"Character pool: %s\n",charpool); + } + charpoolsize = strlen(charpool); +} + + +/* initialize random number generator */ + +void initrandom() { + char err_buf[1024]; +#ifdef USE_NSS_RANDOM + if( NSS_Initialize( "", + "", + "", + "", + NSS_INIT_NOCERTDB | + NSS_INIT_NOMODDB | + NSS_INIT_FORCEOPEN ) != SECSuccess ) { + sprintf(err_buf,"Couldn't initialize NSS (error code %d)\n",PR_GetError()); + errcode = 9; + exitError(err_buf); + } +#else + srand(time(NULL)); +#endif + +} + + +unsigned short getRandomShort() { + unsigned short r; +#ifdef USE_NSS_RANDOM + PK11_GenerateRandom( ( unsigned char * ) &r, sizeof( r ) ); + if (o_debug) { + /* fprintf(stderr,"Random: %d\n",r); */ + } + return r; +#else + return (unsigned short) rand(); +#endif +} + + +/* + * this function is important. It needs review. + * + * returns a random number in the range (0 .. max-1) + */ + +/* We have a short, rno, and we want to convert this to a number + in the required range by just using (rno % max). However, + this may result in some of the numbers at the end of 'rno's + range being selected more frequently. So, if random number + select is in this range, we will pick another. + + As an example, assume: + a short is 4 bits (0..15) + max is 6 + + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + a a a a a a b b b b b b X X X X + + we want to reject everything more than 11 + + we take 16 (that largest number which can be in a short+1) + divide by 'max', which is 6. This gives us 2. Multiply by + max, gives us 12. Subtract 1, which is 11, our highest + allowable range. Now we do the modulus. + +*/ + +unsigned short getRandomInRange(unsigned short max) { + unsigned short rno; + unsigned short result; + + unsigned short max_allowed_rno = + ((65536 / max) * max) -1; + + do { + rno = getRandomShort(); + } while (rno >max_allowed_rno); + + result = rno % max; + + assert(result < max); + + return result; +} + + +char * newPassword() { + static char *pw_buf=NULL; + unsigned short l; + unsigned short r; + int i; + + if (pw_buf == NULL) { + pw_buf = (char *) malloc(i_maxlength+5); + } + + if (charpool == NULL) { + buildCharpool(); + } + + /* decide how long the password should be */ + /* It must be between i_minlength and i_maxlength */ + + if (i_minlength == i_maxlength) { + l = i_minlength; + } else { + l = getRandomInRange((unsigned short)(1 + i_maxlength - i_minlength)); + l += i_minlength; + } + + for (i=0; i<l; i++) { + r = getRandomInRange((unsigned short)(charpoolsize)); + pw_buf[i] = charpool[r]; + } + pw_buf[l] = '\0'; + return pw_buf; +} + + +void testpingen() { + int count=25; + int i,j; + int pwlen; + char *pw; + unsigned int index[256]; + unsigned int *totals; + char c; + + if (! equals(o_testpingen,"")) { + count = atoi(o_testpingen); + } + + if (charpool == NULL) { + buildCharpool(); + } + + /* last spot is used to hold invalid chars */ + totals = malloc(sizeof(int)*(charpoolsize+1)); + if (totals != NULL) { + for (i=0;i<(charpoolsize);i++) { + totals[i] = 0; + } + totals[charpoolsize]=0; + for (i=0;i<256;i++) { + index[i] = 255; /* indicates->invalid */ + } + for (i=0;i<charpoolsize;i++) { + index[(int)(charpool[i])] = i; + } + + for (i=0;i<count;i++) { + pw = newPassword(); + if (pw != NULL) { + if (o_debug) { + fprintf(output,"%d:%s\n",i+1,pw); + } + pwlen = strlen(pw); + for (j=0;j<pwlen;j++) { + c = pw[j]; + if (index[(int)c] == 255) { + printf("\ninvalid char found: %02x %c\n",c,c); + totals[charpoolsize]++; + } + else { + totals[index[(int)c]]++; + } + } + free(pw); + } + } + + for (i=0;i<charpoolsize;i++) { + fprintf(output,"%c: %10d\n",charpool[i],totals[i]); + } + fprintf(output,"invalid: %10d\n",totals[charpoolsize]); + free(totals); + } +} + + + diff --git a/base/native-tools/src/setpin/setpin.conf b/base/native-tools/src/setpin/setpin.conf new file mode 100644 index 000000000..4e5851858 --- /dev/null +++ b/base/native-tools/src/setpin/setpin.conf @@ -0,0 +1,83 @@ +# --- 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2007 Red Hat, Inc. +# All rights reserved. +# --- END COPYRIGHT BLOCK --- +# +# +# Setpin has a special setup mode which allows you to +# automate the following two tasks. +# +# * To enable setpin to operate, the directory schema must be +# changed to add the pin attribute and pinPerson objectclass. +# +# * To enable pin removal to work well, you can create a new +# pin user with an ACI which lets the user remove the pin +# +# This configuration file is used as an input for setpin. +# After modifying the options in this file, invoke setpin +# with this config file: +# +# setpin optfile=setpin.conf + + +########## GENERAL INFO ABOUT YOUR DIRECTORY ##### + + +#------- Enter the hostname of the LDAP server +host=localhost + +#------- Enter the port number of the LDAP server +port=389 + +#------- Enter the DN of the Directory Manager user +binddn=CN=Directory Manager + +#------- Enter the password for the Directory manager user +bindpw= + + + +################ SCHEMA MODIFICATIONS ####### +# +# Comment-out to turn off schema modification +schemachange=yes + +# Enter the pin attribute name +attribute=pin + +# Enter the pin objectclass +objectclass=pinPerson + + +############### PIN REMOVAL ########## +# +# To enable pin removal, it is advisable to create a new +# user who has the power to remove pins, and nothing else. +# +# Enter the DN and password for the new pin manager user +pinmanager=cn=pinmanager,o=mcom.com +pinmanagerpwd= + +# Enter the base over which this user has the power +# to remove pins +basedn=ou=people,o=mcom.com + + + +## This line switches setpin into setup mode. +## Please do not change it. +setup=yes + diff --git a/base/native-tools/src/setpin/setpin_options.c b/base/native-tools/src/setpin/setpin_options.c new file mode 100644 index 000000000..d8ee83a8c --- /dev/null +++ b/base/native-tools/src/setpin/setpin_options.c @@ -0,0 +1,290 @@ +/* --- 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + +/* Set-pin tool */ + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> +#include <stdlib.h> + +extern int OPT_getValue(char *option, char **output); +extern void exitError(char *errstring); +extern int errcode; + +#define PW_DEFAULT_LENGTH 6 +#define ERR_BUF_LENGTH 512 + +char *valid_args[] = { + "host", "LDAP host [required]", + "port", "LDAP port (default 389)", + "binddn", "DN to bind to directory as [required]", + "bindpw", "Password associated with above DN ", + "filter", "Ldap search filter e.g. filter=(uid=*) [required]", +/* "ssl", "Use SSL LDAP connection?", */ +/* "certdb", "Path to SSL Client certificate database directory (not yet implemented)", + "nickname", "Nickname of cert to use for SSL client auth (not yet implemented)", + */ + "basedn", "Base DN used for LDAP search", + "length", "Length of generated pins (default 6)", + "minlength","Minimum length of generated pins (not to be used with 'length')", + "maxlength","Maximum length of generated pins (not to be used with 'length')", + "gen", "Permitted chars for pin. Type 'setpin gen' for more info", + "case", "Restrict case of pins 'case=upperonly'", + "objectclass", "Objectclass of LDAP entry to operate on (default pinPerson)", + "attribute","Which LDAP attribute to write to (default pin)", + "hash", "Hash algorithm used to store pin: 'none', 'md5' or 'sha1' (default)", + "saltattribute", "Which attribute to use for salt (default: dn)", + "input", "File to use for restricting DN's, or providing your own pins", + "output", "Redirect stdout to a file", + "write", "Turn on writing to directory (otherwise, pins will not get written)", + "clobber", "Overwrite old pins in the directory", + "testpingen", "Test pin generation mode. testpingen=count", + "debug", "Turn on debugging, or use debug=attrs for even more", + "optfile", "Read in options (one per line) from specified file", + "setup", "Switch to setup mode", + "pinmanager","Pin Manager user to create in setup mode", + "pinmanagerpwd","password of pin manager user in setup mode", + "schemachange","make schema changes in setup mode", + NULL +}; + +int valid_args_len = sizeof(valid_args)/sizeof(char *); + +int i_length, i_minlength, i_maxlength; + +char *attribute=NULL; + +char *o_certdb,*o_nickname,*o_binddn,*o_bindpw,*o_filter,*o_ssl, + *o_basedn,*o_input,*o_host,*o_port,*o_length,*o_minlength,*o_hash, + *o_maxlength,*o_gen,*o_case,*o_attribute,*o_objectclass,*o_output, + *o_retry,*o_debug, *o_write, *o_clobber, *o_saltattribute, *o_testpingen, + *o_setup,*o_pinmanager,*o_pinmanagerpwd,*o_schemachange; + +void setDefaultOptions() { + o_certdb= "."; + o_nickname= NULL; + o_binddn= NULL; + o_bindpw= NULL; + o_filter= NULL; + o_ssl= NULL; + o_basedn= NULL; + o_input= NULL; + o_host= NULL; + o_port= NULL; + o_length= NULL; /* default set later */ + o_minlength=NULL; + o_maxlength=NULL; + o_gen= "RNG-alphanum"; + o_case= NULL; + o_attribute="pin"; + o_hash= "sha1"; + o_objectclass="pinPerson"; + o_output= NULL; + o_retry= "5"; + o_debug= NULL; + o_write= NULL; + o_clobber= NULL; + o_saltattribute = NULL; + o_testpingen = NULL; + o_setup= NULL; + o_pinmanager= NULL; + o_pinmanagerpwd= NULL; + o_schemachange= NULL; +} + +void getOptions() { + int i; + char *c; + + i_length = 0; + i_minlength =0; + i_maxlength =0; + + OPT_getValue("certdb", &o_certdb); + OPT_getValue("nickname", &o_nickname); + OPT_getValue("binddn", &o_binddn); + OPT_getValue("bindpw", &o_bindpw); + OPT_getValue("filter", &o_filter); + i = OPT_getValue("ssl", &o_ssl); + if (i) o_ssl = "yes"; + OPT_getValue("basedn", &o_basedn); + OPT_getValue("input", &o_input); + OPT_getValue("host", &o_host); + OPT_getValue("port", &o_port); + OPT_getValue("length", &o_length); + if (o_length) i_length = atoi(o_length); + OPT_getValue("minlength",&o_minlength); + if (o_minlength) i_minlength = atoi(o_minlength); + OPT_getValue("maxlength",&o_maxlength); + if (o_maxlength) i_maxlength = atoi(o_maxlength); + OPT_getValue("gen", &o_gen); + OPT_getValue("case", &o_case); + OPT_getValue("attribute",&o_attribute); + OPT_getValue("hash", &o_hash); + if (o_hash) { + c = o_hash; + while (*c) { + if (isupper(*c)) { + *c = *c - 'A' + 'a'; + } + c++; + } + } + + OPT_getValue("objectclass",&o_objectclass); + OPT_getValue("output", &o_output); + OPT_getValue("retry", &o_retry); + i = OPT_getValue("debug", &o_debug); + if (i) { + if (! o_debug) { + o_debug = "yes"; + } + } + i = OPT_getValue("write", &o_write); + if (i) o_write = "yes"; + i = OPT_getValue("clobber", &o_clobber); + if (i) o_clobber = "yes"; + OPT_getValue("saltattribute", &o_saltattribute); + i = OPT_getValue("testpingen", &o_testpingen); + if (i) { + if (!o_testpingen) { + o_testpingen = "25"; + } + } + OPT_getValue("setup", &o_setup); + OPT_getValue("pinmanager", &o_pinmanager); + OPT_getValue("pinmanagerpwd", &o_pinmanagerpwd); + OPT_getValue("schemachange", &o_schemachange); + + +} + +int equals(char *s, char *t) { + return !(strcmp(s,t)); +} + +void validateOptions() { + char errbuf[ERR_BUF_LENGTH]; + + if (o_nickname && equals(o_ssl,"no")) { + snprintf(errbuf, ERR_BUF_LENGTH, "specifying nickname doesn't make sense with no SSL"); + goto loser; + } + + if (o_gen == NULL || ! + ( equals(o_gen,"RNG-printableascii") || + equals(o_gen,"RNG-alpha") || + equals(o_gen,"RNG-alphanum") || + equals(o_gen,"FIPS181-printable")) + ) { + printf("Permissible values for gen:\n" + " RNG-alpha : alpha-only characters\n" + " RNG-alphanum : alphanumeric characters\n" + " RNG-printableascii : alphanumeric and punctuation\n"); + if (o_gen) { + printf("You specified: gen=%s\n",o_gen); + } + exit(0); + } + + if (o_length && (o_minlength || o_maxlength)) { + strcpy(errbuf,"cannot use minlength or maxlength with length option"); + goto loser; + } + + if (o_minlength && !o_maxlength) { + strcpy(errbuf,"if you set minlength, you must also set maxlength"); + goto loser; + } + + if (!o_minlength && o_maxlength) { + strcpy(errbuf,"if you set maxlength, you must also set minlength"); + goto loser; + } + + if (i_minlength > i_maxlength) { + strcpy(errbuf,"cannot set minlength to be more than maxlength"); + goto loser; + } + + if (i_length > 0) { + i_minlength = i_length; + i_maxlength = i_length; + } + else { + if (i_minlength == 0 && i_maxlength == 0) { + i_minlength = PW_DEFAULT_LENGTH; + i_maxlength = PW_DEFAULT_LENGTH; + } + } + + if (o_testpingen) { + return; + } + + if (!o_host || equals(o_host,"")) { + strcpy(errbuf,"host missing"); + goto loser; + } + + if (!o_binddn || equals(o_binddn,"")) { + strcpy(errbuf,"binddn missing"); + goto loser; + } + + if (!o_bindpw || equals(o_bindpw,"")) { + strcpy(errbuf,"bindpw missing"); + goto loser; + } + + if (o_setup != NULL) { + return; + } + + if (!o_basedn) { + fprintf(stderr,"WARNING: basedn not set. Will search from root.\n"); + } + + if (!o_filter || equals(o_filter,"")) { + strcpy(errbuf,"filter missing. Example filters:\n filter=(uid=*) - all users with a UID attribute\n filter=(&(uid=*)(ou=Managers)) - all users with a UID and members of the managers group\n"); + goto loser; + } + + if (! + (equals(o_hash,"sha1") || + equals(o_hash,"md5") || + equals(o_hash,"none")) + ) { + snprintf(errbuf, ERR_BUF_LENGTH, "invalid hash: %s",o_hash); + goto loser; + } + if (equals(o_hash,"none")) o_hash = NULL; + + return ; + + loser: + errcode=13; + exitError(errbuf); + +} + + diff --git a/base/native-tools/src/setpin/setpin_options.h b/base/native-tools/src/setpin/setpin_options.h new file mode 100644 index 000000000..45373f356 --- /dev/null +++ b/base/native-tools/src/setpin/setpin_options.h @@ -0,0 +1,56 @@ +/* --- 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2007 Red Hat, Inc. + * All rights reserved. + * --- END COPYRIGHT BLOCK --- + */ + + +#ifndef SETPIN_OPTIONS_H +#define SETPIN_OPTIONS_H + +#ifdef HAVE_CONFIG_H +#ifndef AUTOTOOLS_CONFIG_H +#define AUTOTOOLS_CONFIG_H + +/* Eliminate warnings when using Autotools */ +#undef PACKAGE_BUGREPORT +#undef PACKAGE_NAME +#undef PACKAGE_STRING +#undef PACKAGE_TARNAME +#undef PACKAGE_VERSION + +#include <config.h> +#endif /* AUTOTOOLS_CONFIG_H */ +#endif /* HAVE_CONFIG_H */ + +extern char *o_certdb,*o_nickname,*o_binddn,*o_bindpw,*o_bindpwfile,*o_filter,*o_ssl, + *o_input,*o_basedn,*o_dnfile,*o_host,*o_port,*o_length,*o_minlength, + *o_maxlength,*o_gen,*o_case,*o_attribute,*o_hash,*o_objectclass,*o_output, + *o_retry,*o_debug,*o_write,*o_clobber,*o_saltattribute,*o_testpingen,*o_setup, + *o_pinmanager,*o_pinmanagerpwd,*o_schemachange; + +extern char *valid_args[]; +extern int valid_args_len; + +extern void setDefaultOptions(); +extern void getOptions(); +extern void validateOptions(); + +extern int i_length, i_minlength, i_maxlength; + +extern char* attribute; + +#endif |