xref: /freebsd/crypto/krb5/src/lib/kadm5/srv/pwqual_hesiod.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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