]> eyrie.org Git - kerberos/krb5-strength.git/blob - tools/heimdal-strength.c
Merge pull request #4 from dariaphoebe/main
[kerberos/krb5-strength.git] / tools / heimdal-strength.c
1 /*
2  * Password strength checking program for Heimdal.
3  *
4  * This is a wrapper around the krb5-strength-modified version of CrackLib
5  * that supports the Heimdal external password strength check program
6  * interface.  It uses a krb5.conf parameter to determine the location of its
7  * dictionary.
8  *
9  * Written by Russ Allbery <eagle@eyrie.org>
10  * Copyright 2020 Russ Allbery <eagle@eyrie.org>
11  * Copyright 2009, 2013
12  *     The Board of Trustees of the Leland Stanford Junior University
13  *
14  * SPDX-License-Identifier: MIT
15  */
16
17 #include <config.h>
18 #include <portable/krb5.h>
19 #include <portable/system.h>
20
21 #include <errno.h>
22
23 #include <plugin/internal.h>
24 #include <util/macros.h>
25 #include <util/messages-krb5.h>
26 #include <util/messages.h>
27 #include <util/xmalloc.h>
28
29
30 /*
31  * Read a key/value pair from stdin, check that the key is the one expected,
32  * and if so, copy the value into the provided buffer.  Exits with an
33  * appropriate error on failure.
34  */
35 static void
36 read_key(const char *key, char *buffer, size_t length)
37 {
38     char *p;
39     int size = (length < INT_MAX) ? (int) length : INT_MAX;
40
41     if (fgets(buffer, size, stdin) == NULL)
42         sysdie("Cannot read %s", key);
43     if (strlen(buffer) < 1 || buffer[strlen(buffer) - 1] != '\n')
44         die("Malformed or too long %s line", key);
45     buffer[strlen(buffer) - 1] = '\0';
46     if (strncmp(buffer, key, strlen(key)) != 0)
47         die("Malformed %s line", key);
48     p = buffer + strlen(key);
49     if (p[0] != ':' || p[1] != ' ')
50         die("Malformed %s line", key);
51     p += 2;
52     memmove(buffer, p, strlen(p) + 1);
53 }
54
55
56 /*
57  * Read a principal and password from standard input and do strength checking
58  * on that principal and password, returning the results expected by the
59  * Heimdal external-check interface.  Takes the password strength checking
60  * context.
61  */
62 static void
63 check_password(krb5_context ctx, krb5_pwqual_moddata data)
64 {
65     char principal[BUFSIZ], password[BUFSIZ], end[BUFSIZ];
66     krb5_error_code code;
67     const char *message;
68
69     read_key("principal", principal, sizeof(principal));
70     read_key("new-password", password, sizeof(password));
71     if (fgets(end, sizeof(end), stdin) == NULL)
72         sysdie("Cannot read end of entry");
73     if (strcmp(end, "end\n") != 0)
74         die("Malformed end line");
75     code = strength_check(ctx, data, principal, password);
76     if (code == 0)
77         printf("APPROVED\n");
78     else {
79         message = krb5_get_error_message(ctx, code);
80         fprintf(stderr, "%s\n", message);
81         krb5_free_error_message(ctx, message);
82     }
83 }
84
85
86 /*
87  * Main routine.  There will be one argument, the principal, but we ignore it
88  * (we get it again via the input data).
89  *
90  * Heimdal 1.3 appears to pass the principal as argv[0], where the name of the
91  * program would normally be, so allow for that behavior as well.
92  */
93 int
94 main(int argc, char *argv[] UNUSED)
95 {
96     krb5_context ctx;
97     krb5_error_code code;
98     krb5_pwqual_moddata data;
99
100     /* Check command-line arguments. */
101     if (argc != 1 && argc != 2)
102         die("Usage: heimdal-strength <principal>");
103
104     /* Initialize Kerberos and the module. */
105     code = krb5_init_context(&ctx);
106     if (code != 0)
107         die_krb5(ctx, code, "Cannot create Kerberos context");
108     code = strength_init(ctx, NULL, &data);
109     if (code != 0)
110         die_krb5(ctx, code, "Cannot initialize strength checking");
111
112     /* Check the password and report results. */
113     check_password(ctx, data);
114
115     /* Close and free resources. */
116     strength_close(ctx, data);
117     krb5_free_context(ctx);
118     exit(0);
119 }