155682Smarkm/*
2233294Sstas * Copyright (c) 1998, 1999 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "kadmin_locl.h"
3555682Smarkm
3655682Smarkm/* This file defines some a function that generates a random password,
3755682Smarkm   that can be used when creating a large amount of principals (such
3855682Smarkm   as for a batch of students). Since this is a political matter, you
3955682Smarkm   should think about how secure generated passwords has to be.
40233294Sstas
4155682Smarkm   Both methods defined here will give you at least 55 bits of
4255682Smarkm   entropy.
4355682Smarkm   */
4455682Smarkm
4555682Smarkm/* If you want OTP-style passwords, define OTP_STYLE */
4655682Smarkm
4755682Smarkm#ifdef OTP_STYLE
4855682Smarkm#include <otp.h>
4955682Smarkm#else
5055682Smarkmstatic void generate_password(char **pw, int num_classes, ...);
5155682Smarkm#endif
5255682Smarkm
5355682Smarkmvoid
5455682Smarkmrandom_password(char *pw, size_t len)
5555682Smarkm{
5655682Smarkm#ifdef OTP_STYLE
5755682Smarkm    {
5878527Sassar	OtpKey newkey;
5955682Smarkm
6078527Sassar	krb5_generate_random_block(&newkey, sizeof(newkey));
6155682Smarkm	otp_print_stddict (newkey, pw, len);
6255682Smarkm	strlwr(pw);
6355682Smarkm    }
6455682Smarkm#else
6555682Smarkm    char *pass;
66233294Sstas    generate_password(&pass, 3,
67233294Sstas		      "abcdefghijklmnopqrstuvwxyz", 7,
68233294Sstas		      "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 2,
6955682Smarkm		      "@$%&*()-+=:,/<>1234567890", 1);
7055682Smarkm    strlcpy(pw, pass, len);
7155682Smarkm    memset(pass, 0, strlen(pass));
7255682Smarkm    free(pass);
7355682Smarkm#endif
7455682Smarkm}
7555682Smarkm
7655682Smarkm/* some helper functions */
7755682Smarkm
7855682Smarkm#ifndef OTP_STYLE
7955682Smarkm/* return a random value in range 0-127 */
8055682Smarkmstatic int
8178527SassarRND(unsigned char *key, int keylen, int *left)
8255682Smarkm{
8355682Smarkm    if(*left == 0){
8478527Sassar	krb5_generate_random_block(key, keylen);
8578527Sassar	*left = keylen;
8655682Smarkm    }
8755682Smarkm    (*left)--;
8855682Smarkm    return ((unsigned char*)key)[*left];
8955682Smarkm}
9055682Smarkm
9155682Smarkm/* This a helper function that generates a random password with a
9255682Smarkm   number of characters from a set of character classes.
9355682Smarkm
9455682Smarkm   If there are n classes, and the size of each class is Pi, and the
9555682Smarkm   number of characters from each class is Ni, the number of possible
9655682Smarkm   passwords are (given that the character classes are disjoint):
9755682Smarkm
9855682Smarkm     n             n
9955682Smarkm   -----        /  ----  \
10055682Smarkm   |   |  Ni    |  \     |
10155682Smarkm   |   | Pi     |   \  Ni| !
10255682Smarkm   |   | ---- * |   /    |
10355682Smarkm   |   | Ni!    |  /___  |
10455682Smarkm    i=1          \  i=1  /
105233294Sstas
10655682Smarkm    Since it uses the RND function above, neither the size of each
10755682Smarkm    class, nor the total length of the generated password should be
10855682Smarkm    larger than 127 (without fixing RND).
109233294Sstas
11055682Smarkm   */
11155682Smarkmstatic void
11255682Smarkmgenerate_password(char **pw, int num_classes, ...)
11355682Smarkm{
11455682Smarkm    struct {
11555682Smarkm	const char *str;
11655682Smarkm	int len;
11755682Smarkm	int freq;
11855682Smarkm    } *classes;
11955682Smarkm    va_list ap;
12055682Smarkm    int len, i;
12178527Sassar    unsigned char rbuf[8]; /* random buffer */
12255682Smarkm    int rleft = 0;
12355682Smarkm
124178825Sdfr    *pw = NULL;
125178825Sdfr
12655682Smarkm    classes = malloc(num_classes * sizeof(*classes));
127178825Sdfr    if(classes == NULL)
128178825Sdfr	return;
12955682Smarkm    va_start(ap, num_classes);
13055682Smarkm    len = 0;
13155682Smarkm    for(i = 0; i < num_classes; i++){
13255682Smarkm	classes[i].str = va_arg(ap, const char*);
13355682Smarkm	classes[i].len = strlen(classes[i].str);
13455682Smarkm	classes[i].freq = va_arg(ap, int);
13555682Smarkm	len += classes[i].freq;
13655682Smarkm    }
13755682Smarkm    va_end(ap);
13855682Smarkm    *pw = malloc(len + 1);
139178825Sdfr    if(*pw == NULL) {
140178825Sdfr	free(classes);
14155682Smarkm	return;
142178825Sdfr    }
14355682Smarkm    for(i = 0; i < len; i++) {
14455682Smarkm	int j;
14578527Sassar	int x = RND(rbuf, sizeof(rbuf), &rleft) % (len - i);
14655682Smarkm	int t = 0;
14755682Smarkm	for(j = 0; j < num_classes; j++) {
14855682Smarkm	    if(x < t + classes[j].freq) {
14978527Sassar		(*pw)[i] = classes[j].str[RND(rbuf, sizeof(rbuf), &rleft)
15078527Sassar					 % classes[j].len];
15155682Smarkm		classes[j].freq--;
15255682Smarkm		break;
15355682Smarkm	    }
15455682Smarkm	    t += classes[j].freq;
15555682Smarkm	}
15655682Smarkm    }
15755682Smarkm    (*pw)[len] = '\0';
15855682Smarkm    memset(rbuf, 0, sizeof(rbuf));
15955682Smarkm    free(classes);
16055682Smarkm}
16155682Smarkm#endif
162