1 /* 2 * Support functions for pam-krb5. 3 * 4 * Some general utility functions used by multiple PAM groups that aren't 5 * associated with any particular chunk of functionality. 6 * 7 * Copyright 2005-2007, 2009, 2020 Russ Allbery <eagle@eyrie.org> 8 * Copyright 2011-2012 9 * The Board of Trustees of the Leland Stanford Junior University 10 * Copyright 2005 Andres Salomon <dilinger@debian.org> 11 * Copyright 1999-2000 Frank Cusack <fcusack@fcusack.com> 12 * 13 * SPDX-License-Identifier: BSD-3-clause or GPL-1+ 14 */ 15 16 #include <config.h> 17 #include <portable/krb5.h> 18 #include <portable/pam.h> 19 #include <portable/system.h> 20 21 #include <errno.h> 22 #include <pwd.h> 23 24 #include <module/internal.h> 25 #include <pam-util/args.h> 26 #include <pam-util/logging.h> 27 28 29 /* 30 * Given the PAM arguments and the user we're authenticating, see if we should 31 * ignore that user because they're root or have a low-numbered UID and we 32 * were configured to ignore such users. Returns true if we should ignore 33 * them, false otherwise. Ignores any fully-qualified principal names. 34 */ 35 int 36 pamk5_should_ignore(struct pam_args *args, PAM_CONST char *username) 37 { 38 struct passwd *pwd; 39 40 if (args->config->ignore_root && strcmp("root", username) == 0) { 41 putil_debug(args, "ignoring root user"); 42 return 1; 43 } 44 if (args->config->minimum_uid > 0 && strchr(username, '@') == NULL) { 45 pwd = pam_modutil_getpwnam(args->pamh, username); 46 if (pwd != NULL && pwd->pw_uid < (uid_t) args->config->minimum_uid) { 47 putil_debug(args, "ignoring low-UID user (%lu < %ld)", 48 (unsigned long) pwd->pw_uid, 49 args->config->minimum_uid); 50 return 1; 51 } 52 } 53 return 0; 54 } 55 56 57 /* 58 * Verify the user authorization. Call krb5_kuserok if this is a local 59 * account, or do the krb5_aname_to_localname verification if ignore_k5login 60 * was requested. For non-local accounts, the principal must match the 61 * authentication identity. 62 */ 63 int 64 pamk5_authorized(struct pam_args *args) 65 { 66 struct context *ctx; 67 krb5_context c; 68 krb5_error_code retval; 69 int status; 70 struct passwd *pwd; 71 char kuser[65]; /* MAX_USERNAME == 65 (MIT Kerberos 1.4.1). */ 72 73 if (args == NULL || args->config == NULL || args->config->ctx == NULL 74 || args->config->ctx->context == NULL) 75 return PAM_SERVICE_ERR; 76 ctx = args->config->ctx; 77 if (ctx->name == NULL) 78 return PAM_SERVICE_ERR; 79 c = ctx->context; 80 81 /* 82 * If alt_auth_map was set, authorize the user if the authenticated 83 * principal matches the mapped principal. alt_auth_map essentially 84 * serves as a supplemental .k5login. PAM_SERVICE_ERR indicates fatal 85 * errors that should abort remaining processing; PAM_AUTH_ERR indicates 86 * that it just didn't match, in which case we continue to try other 87 * authorization methods. 88 */ 89 if (args->config->alt_auth_map != NULL) { 90 status = pamk5_alt_auth_verify(args); 91 if (status == PAM_SUCCESS || status == PAM_SERVICE_ERR) 92 return status; 93 } 94 95 /* 96 * If the name to which we're authenticating contains @ (is fully 97 * qualified), it must match the principal exactly. 98 */ 99 if (strchr(ctx->name, '@') != NULL) { 100 char *principal; 101 102 retval = krb5_unparse_name(c, ctx->princ, &principal); 103 if (retval != 0) { 104 putil_err_krb5(args, retval, "krb5_unparse_name failed"); 105 return PAM_SERVICE_ERR; 106 } 107 if (strcmp(principal, ctx->name) != 0) { 108 putil_err(args, "user %s does not match principal %s", ctx->name, 109 principal); 110 krb5_free_unparsed_name(c, principal); 111 return PAM_AUTH_ERR; 112 } 113 krb5_free_unparsed_name(c, principal); 114 return PAM_SUCCESS; 115 } 116 117 /* 118 * Otherwise, apply either krb5_aname_to_localname or krb5_kuserok 119 * depending on the situation. 120 */ 121 pwd = pam_modutil_getpwnam(args->pamh, ctx->name); 122 if (args->config->ignore_k5login || pwd == NULL) { 123 retval = krb5_aname_to_localname(c, ctx->princ, sizeof(kuser), kuser); 124 if (retval != 0) { 125 putil_err_krb5(args, retval, "cannot convert principal to user"); 126 return PAM_AUTH_ERR; 127 } 128 if (strcmp(kuser, ctx->name) != 0) { 129 putil_err(args, "user %s does not match local name %s", ctx->name, 130 kuser); 131 return PAM_AUTH_ERR; 132 } 133 } else { 134 if (!krb5_kuserok(c, ctx->princ, ctx->name)) { 135 putil_err(args, "krb5_kuserok for user %s failed", ctx->name); 136 return PAM_AUTH_ERR; 137 } 138 } 139 140 return PAM_SUCCESS; 141 } 142