4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <security/pam_appl.h>
38 extern const char *error_message(long);
40 /* ******************************************************************** */
42 /* Utilities Functions */
44 /* ******************************************************************** */
48 * To get the uid from the passwd entry for specified user
49 * It returns 0 if the user can't be found, otherwise returns 1.
52 get_pw_uid(char *user
, uid_t
*uid
)
57 if (getpwnam_r(user
, &sp
, buffer
, sizeof (buffer
)) == NULL
) {
68 * To get the gid from the passwd entry for specified user
69 * It returns 0 if the user can't be found, otherwise returns 1.
72 get_pw_gid(char *user
, gid_t
*gid
)
77 if (getpwnam_r(user
, &sp
, buffer
, sizeof (buffer
)) == NULL
) {
89 * To get the kerberos user name for the specified user.
90 * Assumes that the kuser string is allocated. It will be
91 * overwritten. This saves us having to deal will allocating
92 * and freeing the kuser string.
94 * RFC 1510 does not mention how to handle mixed case domainnames
95 * while constructing client principals. So we will follow the same
96 * procedure as for server principals and lowercase the domainname.
99 * PAM_BUF_ERR - if there is an error from krb5_sname_to_principal(),
100 * or krb5_unparse_name()
101 * 0 - if there was no error
104 get_kmd_kuser(krb5_context kcontext
, const char *user
, char *kuser
, int length
)
106 if (strcmp(user
, ROOT_UNAME
) == 0) {
107 krb5_principal princ
;
108 char *name
, *princname
, *lasts
;
110 if (krb5_sname_to_principal(kcontext
, NULL
, ROOT_UNAME
,
111 KRB5_NT_SRV_HST
, &princ
)) {
112 return (PAM_BUF_ERR
);
114 if (krb5_unparse_name(kcontext
, princ
, &princname
)) {
115 krb5_free_principal(kcontext
, princ
);
116 return (PAM_BUF_ERR
);
118 /* just interested in princ name before the @REALM part */
119 if ((name
= strtok_r(princname
, "@", &lasts
)) == NULL
) {
120 krb5_free_principal(kcontext
, princ
);
122 return (PAM_BUF_ERR
);
124 if (strlcpy(kuser
, name
, length
) >= length
) {
125 krb5_free_principal(kcontext
, princ
);
127 return (PAM_BUF_ERR
);
129 krb5_free_principal(kcontext
, princ
);
132 if (strlcpy(kuser
, user
, length
) >= length
) {
133 return (PAM_BUF_ERR
);
140 * return true (1) if the user's key is in the (default) keytab
143 key_in_keytab(const char *user
, int debug
)
145 krb5_keytab kt_handle
;
146 krb5_keytab_entry kt_ent
;
147 char *whoami
= "key_in_keytab";
148 krb5_error_code retval
= 0;
149 krb5_error_code code
= 0;
150 krb5_context kcontext
= NULL
;
151 krb5_principal princ
= NULL
;
152 char kuser
[2*MAXHOSTNAMELEN
];
156 __pam_log(LOG_AUTH
| LOG_DEBUG
,
157 "PAM-KRB5 (%s): start for user '%s'",
158 whoami
, user
? user
: "<null>");
163 /* need to free context with krb5_free_context */
164 if (code
= krb5_init_secure_context(&kcontext
)) {
166 __pam_log(LOG_AUTH
| LOG_DEBUG
,
167 "PAM-KRB5 (%s): Error initializing "
169 error_message(code
));
173 if ((code
= get_kmd_kuser(kcontext
, (const char *)user
, kuser
,
174 2*MAXHOSTNAMELEN
)) != 0) {
178 /* need to free princ with krb5_free_principal */
179 if ((code
= krb5_parse_name(kcontext
, kuser
, &princ
)) != 0) {
181 __pam_log(LOG_AUTH
| LOG_DEBUG
,
182 "PAM-KRB5 (%s): can't parse name (%s)",
183 whoami
, error_message(code
));
187 /* need to close keytab handle with krb5_kt_close */
188 if ((code
= krb5_kt_default(kcontext
, &kt_handle
))) {
190 __pam_log(LOG_AUTH
| LOG_DEBUG
,
191 "PAM-KRB5 (%s): krb5_kt_default failed (%s)",
192 whoami
, error_message(code
));
196 code
= krb5_kt_get_entry(kcontext
, kt_handle
, princ
, 0, 0, &kt_ent
);
198 if (code
== ENOENT
) {
200 __pam_log(LOG_AUTH
| LOG_DEBUG
,
202 "Keytab does not exist",
204 } else if (code
== KRB5_KT_NOTFOUND
) {
206 __pam_log(LOG_AUTH
| LOG_DEBUG
,
208 "No entry for principal "
209 "'%s' exists in keytab",
213 __pam_log(LOG_AUTH
| LOG_DEBUG
,
215 "krb5_kt_get_entry failed (%s)",
216 whoami
, error_message(code
));
218 } else { /* Key found in keytab, return success */
219 (void) krb5_kt_free_entry(kcontext
, &kt_ent
);
221 __pam_log(LOG_AUTH
| LOG_DEBUG
,
223 "keytab entry for '%s' found",
228 (void) krb5_kt_close(kcontext
, kt_handle
);
230 if (princ
&& kcontext
)
231 krb5_free_principal(kcontext
, princ
);
234 krb5_free_context(kcontext
);