summaryrefslogtreecommitdiffstats
path: root/pki/base/native-tools/src/setpin
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/native-tools/src/setpin')
-rw-r--r--pki/base/native-tools/src/setpin/CMakeLists.txt43
-rw-r--r--pki/base/native-tools/src/setpin/b64.c102
-rw-r--r--pki/base/native-tools/src/setpin/options.c184
-rw-r--r--pki/base/native-tools/src/setpin/options.h83
-rw-r--r--pki/base/native-tools/src/setpin/setpin.c1237
-rw-r--r--pki/base/native-tools/src/setpin/setpin.conf83
-rw-r--r--pki/base/native-tools/src/setpin/setpin_options.c290
-rw-r--r--pki/base/native-tools/src/setpin/setpin_options.h56
8 files changed, 2078 insertions, 0 deletions
diff --git a/pki/base/native-tools/src/setpin/CMakeLists.txt b/pki/base/native-tools/src/setpin/CMakeLists.txt
new file mode 100644
index 000000000..b32e12b22
--- /dev/null
+++ b/pki/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/pki/base/native-tools/src/setpin/b64.c b/pki/base/native-tools/src/setpin/b64.c
new file mode 100644
index 000000000..1c20f3792
--- /dev/null
+++ b/pki/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/pki/base/native-tools/src/setpin/options.c b/pki/base/native-tools/src/setpin/options.c
new file mode 100644
index 000000000..9e2dab129
--- /dev/null
+++ b/pki/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/pki/base/native-tools/src/setpin/options.h b/pki/base/native-tools/src/setpin/options.h
new file mode 100644
index 000000000..80ccae478
--- /dev/null
+++ b/pki/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/pki/base/native-tools/src/setpin/setpin.c b/pki/base/native-tools/src/setpin/setpin.c
new file mode 100644
index 000000000..f1bf6a8c7
--- /dev/null
+++ b/pki/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/pki/base/native-tools/src/setpin/setpin.conf b/pki/base/native-tools/src/setpin/setpin.conf
new file mode 100644
index 000000000..4e5851858
--- /dev/null
+++ b/pki/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/pki/base/native-tools/src/setpin/setpin_options.c b/pki/base/native-tools/src/setpin/setpin_options.c
new file mode 100644
index 000000000..d8ee83a8c
--- /dev/null
+++ b/pki/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/pki/base/native-tools/src/setpin/setpin_options.h b/pki/base/native-tools/src/setpin/setpin_options.h
new file mode 100644
index 000000000..45373f356
--- /dev/null
+++ b/pki/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