1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/kadm5/srv/pwqual_hesiod.c */
3 /*
4 * Copyright (C) 2010 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 /*
28 * Password quality module to check passwords against GECOS fields of Hesiod
29 * passwd information, if the tree is compiled with Hesiod support.
30 */
31
32 #include "k5-int.h"
33 #include <krb5/pwqual_plugin.h>
34 #include "server_internal.h"
35 #include <ctype.h>
36
37 #ifdef HESIOD
38 #include <pwd.h>
39
40 static char *
reverse(char * str,char * newstr,size_t newstr_size)41 reverse(char *str, char *newstr, size_t newstr_size)
42 {
43 char *p, *q;
44 size_t i;
45
46 i = strlen(str);
47 if (i >= newstr_size)
48 i = newstr_size - 1;
49 p = str + i - 1;
50 q = newstr;
51 q[i] = '\0';
52 for (; i > 0; i--)
53 *q++ = *p--;
54
55 return newstr;
56 }
57
58 static int
str_check_gecos(char * gecos,const char * pwstr)59 str_check_gecos(char *gecos, const char *pwstr)
60 {
61 char *cp, *ncp, *tcp, revbuf[80];
62
63 for (cp = gecos; *cp; ) {
64 /* Skip past punctuation */
65 for (; *cp; cp++)
66 if (isalnum(*cp))
67 break;
68
69 /* Skip to the end of the word */
70 for (ncp = cp; *ncp; ncp++) {
71 if (!isalnum(*ncp) && *ncp != '\'')
72 break;
73 }
74
75 /* Delimit end of word */
76 if (*ncp)
77 *ncp++ = '\0';
78
79 /* Check word to see if it's the password */
80 if (*cp) {
81 if (!strcasecmp(pwstr, cp))
82 return 1;
83 tcp = reverse(cp, revbuf, sizeof(revbuf));
84 if (!strcasecmp(pwstr, tcp))
85 return 1;
86 cp = ncp;
87 } else
88 break;
89 }
90 return 0;
91 }
92 #endif /* HESIOD */
93
94 static krb5_error_code
hesiod_check(krb5_context context,krb5_pwqual_moddata data,const char * password,const char * policy_name,krb5_principal princ,const char ** languages)95 hesiod_check(krb5_context context, krb5_pwqual_moddata data,
96 const char *password, const char *policy_name,
97 krb5_principal princ, const char **languages)
98 {
99 #ifdef HESIOD
100 extern struct passwd *hes_getpwnam();
101 struct passwd *ent;
102 int i, n;
103 const char *cp;
104
105 /* Don't check for principals with no password policy. */
106 if (policy_name == NULL)
107 return 0;
108
109 n = krb5_princ_size(handle->context, princ);
110 for (i = 0; i < n; i++) {
111 ent = hes_getpwnam(cp);
112 if (ent && ent->pw_gecos && str_check_gecos(ent->pw_gecos, password)) {
113 k5_setmsg(context, KADM5_PASS_Q_DICT,
114 _("Password may not match user information."));
115 return KADM5_PASS_Q_DICT;
116 }
117 }
118 #endif /* HESIOD */
119 return 0;
120 }
121
122 krb5_error_code
pwqual_hesiod_initvt(krb5_context context,int maj_ver,int min_ver,krb5_plugin_vtable vtable)123 pwqual_hesiod_initvt(krb5_context context, int maj_ver, int min_ver,
124 krb5_plugin_vtable vtable)
125 {
126 krb5_pwqual_vtable vt;
127
128 if (maj_ver != 1)
129 return KRB5_PLUGIN_VER_NOTSUPP;
130 vt = (krb5_pwqual_vtable)vtable;
131 vt->name = "hesiod";
132 vt->check = hesiod_check;
133 return 0;
134 }
135