random_password.c revision 178825
155682Smarkm/*
255682Smarkm * Copyright (c) 1998, 1999 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "kadmin_locl.h"
3555682Smarkm
36178825SdfrRCSID("$Id: random_password.c 21745 2007-07-31 16:11:25Z lha $");
3755682Smarkm
3855682Smarkm/* This file defines some a function that generates a random password,
3955682Smarkm   that can be used when creating a large amount of principals (such
4055682Smarkm   as for a batch of students). Since this is a political matter, you
4155682Smarkm   should think about how secure generated passwords has to be.
4255682Smarkm
4355682Smarkm   Both methods defined here will give you at least 55 bits of
4455682Smarkm   entropy.
4555682Smarkm   */
4655682Smarkm
4755682Smarkm/* If you want OTP-style passwords, define OTP_STYLE */
4855682Smarkm
4955682Smarkm#ifdef OTP_STYLE
5055682Smarkm#include <otp.h>
5155682Smarkm#else
5255682Smarkmstatic void generate_password(char **pw, int num_classes, ...);
5355682Smarkm#endif
5455682Smarkm
5555682Smarkmvoid
5655682Smarkmrandom_password(char *pw, size_t len)
5755682Smarkm{
5855682Smarkm#ifdef OTP_STYLE
5955682Smarkm    {
6078527Sassar	OtpKey newkey;
6155682Smarkm
6278527Sassar	krb5_generate_random_block(&newkey, sizeof(newkey));
6355682Smarkm	otp_print_stddict (newkey, pw, len);
6455682Smarkm	strlwr(pw);
6555682Smarkm    }
6655682Smarkm#else
6755682Smarkm    char *pass;
6855682Smarkm    generate_password(&pass, 3,
6955682Smarkm		      "abcdefghijklmnopqrstuvwxyz", 7,
7055682Smarkm		      "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 2,
7155682Smarkm		      "@$%&*()-+=:,/<>1234567890", 1);
7255682Smarkm    strlcpy(pw, pass, len);
7355682Smarkm    memset(pass, 0, strlen(pass));
7455682Smarkm    free(pass);
7555682Smarkm#endif
7655682Smarkm}
7755682Smarkm
7855682Smarkm/* some helper functions */
7955682Smarkm
8055682Smarkm#ifndef OTP_STYLE
8155682Smarkm/* return a random value in range 0-127 */
8255682Smarkmstatic int
8378527SassarRND(unsigned char *key, int keylen, int *left)
8455682Smarkm{
8555682Smarkm    if(*left == 0){
8678527Sassar	krb5_generate_random_block(key, keylen);
8778527Sassar	*left = keylen;
8855682Smarkm    }
8955682Smarkm    (*left)--;
9055682Smarkm    return ((unsigned char*)key)[*left];
9155682Smarkm}
9255682Smarkm
9355682Smarkm/* This a helper function that generates a random password with a
9455682Smarkm   number of characters from a set of character classes.
9555682Smarkm
9655682Smarkm   If there are n classes, and the size of each class is Pi, and the
9755682Smarkm   number of characters from each class is Ni, the number of possible
9855682Smarkm   passwords are (given that the character classes are disjoint):
9955682Smarkm
10055682Smarkm     n             n
10155682Smarkm   -----        /  ----  \
10255682Smarkm   |   |  Ni    |  \     |
10355682Smarkm   |   | Pi     |   \  Ni| !
10455682Smarkm   |   | ---- * |   /    |
10555682Smarkm   |   | Ni!    |  /___  |
10655682Smarkm    i=1          \  i=1  /
10755682Smarkm
10855682Smarkm    Since it uses the RND function above, neither the size of each
10955682Smarkm    class, nor the total length of the generated password should be
11055682Smarkm    larger than 127 (without fixing RND).
11155682Smarkm
11255682Smarkm   */
11355682Smarkmstatic void
11455682Smarkmgenerate_password(char **pw, int num_classes, ...)
11555682Smarkm{
11655682Smarkm    struct {
11755682Smarkm	const char *str;
11855682Smarkm	int len;
11955682Smarkm	int freq;
12055682Smarkm    } *classes;
12155682Smarkm    va_list ap;
12255682Smarkm    int len, i;
12378527Sassar    unsigned char rbuf[8]; /* random buffer */
12455682Smarkm    int rleft = 0;
12555682Smarkm
126178825Sdfr    *pw = NULL;
127178825Sdfr
12855682Smarkm    classes = malloc(num_classes * sizeof(*classes));
129178825Sdfr    if(classes == NULL)
130178825Sdfr	return;
13155682Smarkm    va_start(ap, num_classes);
13255682Smarkm    len = 0;
13355682Smarkm    for(i = 0; i < num_classes; i++){
13455682Smarkm	classes[i].str = va_arg(ap, const char*);
13555682Smarkm	classes[i].len = strlen(classes[i].str);
13655682Smarkm	classes[i].freq = va_arg(ap, int);
13755682Smarkm	len += classes[i].freq;
13855682Smarkm    }
13955682Smarkm    va_end(ap);
14055682Smarkm    *pw = malloc(len + 1);
141178825Sdfr    if(*pw == NULL) {
142178825Sdfr	free(classes);
14355682Smarkm	return;
144178825Sdfr    }
14555682Smarkm    for(i = 0; i < len; i++) {
14655682Smarkm	int j;
14778527Sassar	int x = RND(rbuf, sizeof(rbuf), &rleft) % (len - i);
14855682Smarkm	int t = 0;
14955682Smarkm	for(j = 0; j < num_classes; j++) {
15055682Smarkm	    if(x < t + classes[j].freq) {
15178527Sassar		(*pw)[i] = classes[j].str[RND(rbuf, sizeof(rbuf), &rleft)
15278527Sassar					 % classes[j].len];
15355682Smarkm		classes[j].freq--;
15455682Smarkm		break;
15555682Smarkm	    }
15655682Smarkm	    t += classes[j].freq;
15755682Smarkm	}
15855682Smarkm    }
15955682Smarkm    (*pw)[len] = '\0';
16055682Smarkm    memset(rbuf, 0, sizeof(rbuf));
16155682Smarkm    free(classes);
16255682Smarkm}
16355682Smarkm#endif
164