1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <security/pam_appl.h> 30 #include <pwd.h> 31 #include <string.h> 32 #include <stdlib.h> 33 #include <malloc.h> 34 #include <unistd.h> 35 #include <ctype.h> 36 #include <syslog.h> 37 #include <errno.h> 38 39 #include "utils.h" 40 41 extern const char *error_message(long); 42 43 /* ******************************************************************** */ 44 /* */ 45 /* Utilities Functions */ 46 /* */ 47 /* ******************************************************************** */ 48 49 /* 50 * get_pw_uid(): 51 * To get the uid from the passwd entry for specified user 52 * It returns 0 if the user can't be found, otherwise returns 1. 53 */ 54 int 55 get_pw_uid(char *user, uid_t *uid) 56 { 57 struct passwd sp; 58 char buffer[1024]; 59 60 if (getpwnam_r(user, &sp, buffer, sizeof (buffer)) == NULL) { 61 return (0); 62 } 63 64 *uid = sp.pw_uid; 65 66 return (1); 67 } 68 69 /* 70 * get_pw_gid(): 71 * To get the gid from the passwd entry for specified user 72 * It returns 0 if the user can't be found, otherwise returns 1. 73 */ 74 int 75 get_pw_gid(char *user, gid_t *gid) 76 { 77 struct passwd sp; 78 char buffer[1024]; 79 80 if (getpwnam_r(user, &sp, buffer, sizeof (buffer)) == NULL) { 81 return (0); 82 } 83 84 *gid = sp.pw_gid; 85 86 return (1); 87 } 88 89 90 /* 91 * get_kmd_kuser(): 92 * To get the kerberos user name for the specified user. 93 * Assumes that the kuser string is allocated. It will be 94 * overwritten. This saves us having to deal will allocating 95 * and freeing the kuser string. 96 * 97 * RFC 1510 does not mention how to handle mixed case domainnames 98 * while constructing client principals. So we will follow the same 99 * procedure as for server principals and lowercase the domainname. 100 * 101 * Returns: 102 * PAM_AUTH_ERR - if local host name is not found 103 * PAM_BUF_ERR - if there is an error from krb5_sname_to_principal(), 104 * or krb5_unparse_name() 105 * 0 - if there was no error 106 */ 107 int 108 get_kmd_kuser(krb5_context kcontext, const char *user, char *kuser, int length) 109 { 110 if (strcmp(user, ROOT_UNAME) == 0) { 111 krb5_principal princ; 112 char *name, *princname, *lasts; 113 114 if (krb5_sname_to_principal(kcontext, NULL, ROOT_UNAME, 115 KRB5_NT_SRV_HST, &princ)) { 116 return (PAM_BUF_ERR); 117 } 118 if (krb5_unparse_name(kcontext, princ, &princname)) { 119 krb5_free_principal(kcontext, princ); 120 return (PAM_BUF_ERR); 121 } 122 /* just interested in princ name before the @REALM part */ 123 if ((name = strtok_r(princname, "@", &lasts)) == NULL) { 124 krb5_free_principal(kcontext, princ); 125 free(princname); 126 return (PAM_BUF_ERR); 127 } 128 if (strlcpy(kuser, name, length) >= length) { 129 krb5_free_principal(kcontext, princ); 130 free(princname); 131 return (PAM_BUF_ERR); 132 } 133 krb5_free_principal(kcontext, princ); 134 free(princname); 135 } else { 136 if (strlcpy(kuser, user, length) >= length) { 137 return (PAM_BUF_ERR); 138 } 139 } 140 return (0); 141 } 142 143 /* 144 * return true (1) if the user's key is in the (default) keytab 145 */ 146 int 147 key_in_keytab(const char *user, int debug) 148 { 149 krb5_keytab kt_handle; 150 krb5_keytab_entry kt_ent; 151 char *whoami = "key_in_keytab"; 152 krb5_error_code retval = 0; 153 krb5_error_code code = 0; 154 krb5_context kcontext = NULL; 155 krb5_principal princ = NULL; 156 char kuser[2*MAXHOSTNAMELEN]; 157 158 159 if (debug) 160 syslog(LOG_DEBUG, 161 "PAM-KRB5 (%s): start for user '%s'", 162 whoami, user ? user : "<null>"); 163 164 if (!user) 165 return (retval); 166 167 /* need to free context with krb5_free_context */ 168 if (code = krb5_init_context(&kcontext)) { 169 if (debug) 170 syslog(LOG_DEBUG, 171 "PAM-KRB5 (%s): Error initializing " 172 "krb5: %s", whoami, 173 error_message(code)); 174 return (retval); 175 } 176 177 if ((code = get_kmd_kuser(kcontext, (const char *)user, kuser, 178 2*MAXHOSTNAMELEN)) != 0) { 179 goto out; 180 } 181 182 /* need to free princ with krb5_free_principal */ 183 if ((code = krb5_parse_name(kcontext, kuser, &princ)) != 0) { 184 if (debug) 185 syslog(LOG_DEBUG, 186 "PAM-KRB5 (%s): can't parse name (%s)", 187 whoami, error_message(code)); 188 goto out; 189 } 190 191 /* need to close keytab handle with krb5_kt_close */ 192 if ((code = krb5_kt_default(kcontext, &kt_handle))) { 193 if (debug) 194 syslog(LOG_DEBUG, 195 "PAM-KRB5 (%s): krb5_kt_default failed (%s)", 196 whoami, error_message(code)); 197 goto out; 198 } 199 200 code = krb5_kt_get_entry(kcontext, kt_handle, princ, 0, 0, &kt_ent); 201 if (code != 0) { 202 if (code == ENOENT) { 203 if (debug) 204 syslog(LOG_DEBUG, 205 "PAM-KRB5 (%s): " 206 "Keytab does not exist", 207 whoami); 208 } else if (code == KRB5_KT_NOTFOUND) { 209 if (debug) 210 syslog(LOG_DEBUG, 211 "PAM-KRB5 (%s): " 212 "No entry for principal " 213 "'%s' exists in keytab", 214 whoami, kuser); 215 } else { 216 if (debug) 217 syslog(LOG_DEBUG, 218 "PAM-KRB5 (%s): " 219 "krb5_kt_get_entry failed (%s)", 220 whoami, error_message(code)); 221 } 222 } else { /* Key found in keytab, return success */ 223 (void) krb5_kt_free_entry(kcontext, &kt_ent); 224 if (debug) 225 syslog(LOG_DEBUG, 226 "PAM-KRB5 (%s): " 227 "keytab entry for '%s' found", 228 whoami, user); 229 retval = 1; 230 } 231 232 (void) krb5_kt_close(kcontext, kt_handle); 233 out: 234 if (princ && kcontext) 235 krb5_free_principal(kcontext, princ); 236 237 if (kcontext) 238 krb5_free_context(kcontext); 239 240 return (retval); 241 } 242