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
)
56 struct passwd
*result
;
58 getpwnam_r(user
, &sp
, buffer
, sizeof (buffer
), &result
);
69 * To get the gid from the passwd entry for specified user
70 * It returns 0 if the user can't be found, otherwise returns 1.
73 get_pw_gid(char *user
, gid_t
*gid
)
77 struct passwd
*result
;
79 getpwnam_r(user
, &sp
, buffer
, sizeof (buffer
), &result
);
91 * To get the kerberos user name for the specified user.
92 * Assumes that the kuser string is allocated. It will be
93 * overwritten. This saves us having to deal will allocating
94 * and freeing the kuser string.
96 * RFC 1510 does not mention how to handle mixed case domainnames
97 * while constructing client principals. So we will follow the same
98 * procedure as for server principals and lowercase the domainname.
101 * PAM_BUF_ERR - if there is an error from krb5_sname_to_principal(),
102 * or krb5_unparse_name()
103 * 0 - if there was no error
106 get_kmd_kuser(krb5_context kcontext
, const char *user
, char *kuser
, int length
)
108 if (strcmp(user
, ROOT_UNAME
) == 0) {
109 krb5_principal princ
;
110 char *name
, *princname
, *lasts
;
112 if (krb5_sname_to_principal(kcontext
, NULL
, ROOT_UNAME
,
113 KRB5_NT_SRV_HST
, &princ
)) {
114 return (PAM_BUF_ERR
);
116 if (krb5_unparse_name(kcontext
, princ
, &princname
)) {
117 krb5_free_principal(kcontext
, princ
);
118 return (PAM_BUF_ERR
);
120 /* just interested in princ name before the @REALM part */
121 if ((name
= strtok_r(princname
, "@", &lasts
)) == NULL
) {
122 krb5_free_principal(kcontext
, princ
);
124 return (PAM_BUF_ERR
);
126 if (strlcpy(kuser
, name
, length
) >= length
) {
127 krb5_free_principal(kcontext
, princ
);
129 return (PAM_BUF_ERR
);
131 krb5_free_principal(kcontext
, princ
);
134 if (strlcpy(kuser
, user
, length
) >= length
) {
135 return (PAM_BUF_ERR
);
142 * return true (1) if the user's key is in the (default) keytab
145 key_in_keytab(const char *user
, int debug
)
147 krb5_keytab kt_handle
;
148 krb5_keytab_entry kt_ent
;
149 char *whoami
= "key_in_keytab";
150 krb5_error_code retval
= 0;
151 krb5_error_code code
= 0;
152 krb5_context kcontext
= NULL
;
153 krb5_principal princ
= NULL
;
154 char kuser
[2*MAXHOSTNAMELEN
];
158 __pam_log(LOG_AUTH
| LOG_DEBUG
,
159 "PAM-KRB5 (%s): start for user '%s'",
160 whoami
, user
? user
: "<null>");
165 /* need to free context with krb5_free_context */
166 if (code
= krb5_init_secure_context(&kcontext
)) {
168 __pam_log(LOG_AUTH
| LOG_DEBUG
,
169 "PAM-KRB5 (%s): Error initializing "
171 error_message(code
));
175 if ((code
= get_kmd_kuser(kcontext
, (const char *)user
, kuser
,
176 2*MAXHOSTNAMELEN
)) != 0) {
180 /* need to free princ with krb5_free_principal */
181 if ((code
= krb5_parse_name(kcontext
, kuser
, &princ
)) != 0) {
183 __pam_log(LOG_AUTH
| LOG_DEBUG
,
184 "PAM-KRB5 (%s): can't parse name (%s)",
185 whoami
, error_message(code
));
189 /* need to close keytab handle with krb5_kt_close */
190 if ((code
= krb5_kt_default(kcontext
, &kt_handle
))) {
192 __pam_log(LOG_AUTH
| LOG_DEBUG
,
193 "PAM-KRB5 (%s): krb5_kt_default failed (%s)",
194 whoami
, error_message(code
));
198 code
= krb5_kt_get_entry(kcontext
, kt_handle
, princ
, 0, 0, &kt_ent
);
200 if (code
== ENOENT
) {
202 __pam_log(LOG_AUTH
| LOG_DEBUG
,
204 "Keytab does not exist",
206 } else if (code
== KRB5_KT_NOTFOUND
) {
208 __pam_log(LOG_AUTH
| LOG_DEBUG
,
210 "No entry for principal "
211 "'%s' exists in keytab",
215 __pam_log(LOG_AUTH
| LOG_DEBUG
,
217 "krb5_kt_get_entry failed (%s)",
218 whoami
, error_message(code
));
220 } else { /* Key found in keytab, return success */
221 (void) krb5_kt_free_entry(kcontext
, &kt_ent
);
223 __pam_log(LOG_AUTH
| LOG_DEBUG
,
225 "keytab entry for '%s' found",
230 (void) krb5_kt_close(kcontext
, kt_handle
);
232 if (princ
&& kcontext
)
233 krb5_free_principal(kcontext
, princ
);
236 krb5_free_context(kcontext
);