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 * 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 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 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 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