Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / lib / pam_modules / krb5 / utils.c
blobd78e9795ce124501c2dc6810194257ab6a41e23f
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <security/pam_appl.h>
27 #include <pwd.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <malloc.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <syslog.h>
34 #include <errno.h>
36 #include "utils.h"
38 extern const char *error_message(long);
40 /* ******************************************************************** */
41 /* */
42 /* Utilities Functions */
43 /* */
44 /* ******************************************************************** */
47 * get_pw_uid():
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.
51 int
52 get_pw_uid(char *user, uid_t *uid)
54 struct passwd sp;
55 char buffer[1024];
56 struct passwd *result;
58 getpwnam_r(user, &sp, buffer, sizeof (buffer), &result);
59 if (!result)
60 return (0);
62 *uid = sp.pw_uid;
64 return (1);
68 * get_pw_gid():
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.
72 int
73 get_pw_gid(char *user, gid_t *gid)
75 struct passwd sp;
76 char buffer[1024];
77 struct passwd *result;
79 getpwnam_r(user, &sp, buffer, sizeof (buffer), &result);
80 if (!result)
81 return (0);
83 *gid = sp.pw_gid;
85 return (1);
90 * get_kmd_kuser():
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.
100 * Returns:
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);
123 free(princname);
124 return (PAM_BUF_ERR);
126 if (strlcpy(kuser, name, length) >= length) {
127 krb5_free_principal(kcontext, princ);
128 free(princname);
129 return (PAM_BUF_ERR);
131 krb5_free_principal(kcontext, princ);
132 free(princname);
133 } else {
134 if (strlcpy(kuser, user, length) >= length) {
135 return (PAM_BUF_ERR);
138 return (0);
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];
157 if (debug)
158 __pam_log(LOG_AUTH | LOG_DEBUG,
159 "PAM-KRB5 (%s): start for user '%s'",
160 whoami, user ? user : "<null>");
162 if (!user)
163 return (retval);
165 /* need to free context with krb5_free_context */
166 if (code = krb5_init_secure_context(&kcontext)) {
167 if (debug)
168 __pam_log(LOG_AUTH | LOG_DEBUG,
169 "PAM-KRB5 (%s): Error initializing "
170 "krb5: %s", whoami,
171 error_message(code));
172 return (retval);
175 if ((code = get_kmd_kuser(kcontext, (const char *)user, kuser,
176 2*MAXHOSTNAMELEN)) != 0) {
177 goto out;
180 /* need to free princ with krb5_free_principal */
181 if ((code = krb5_parse_name(kcontext, kuser, &princ)) != 0) {
182 if (debug)
183 __pam_log(LOG_AUTH | LOG_DEBUG,
184 "PAM-KRB5 (%s): can't parse name (%s)",
185 whoami, error_message(code));
186 goto out;
189 /* need to close keytab handle with krb5_kt_close */
190 if ((code = krb5_kt_default(kcontext, &kt_handle))) {
191 if (debug)
192 __pam_log(LOG_AUTH | LOG_DEBUG,
193 "PAM-KRB5 (%s): krb5_kt_default failed (%s)",
194 whoami, error_message(code));
195 goto out;
198 code = krb5_kt_get_entry(kcontext, kt_handle, princ, 0, 0, &kt_ent);
199 if (code != 0) {
200 if (code == ENOENT) {
201 if (debug)
202 __pam_log(LOG_AUTH | LOG_DEBUG,
203 "PAM-KRB5 (%s): "
204 "Keytab does not exist",
205 whoami);
206 } else if (code == KRB5_KT_NOTFOUND) {
207 if (debug)
208 __pam_log(LOG_AUTH | LOG_DEBUG,
209 "PAM-KRB5 (%s): "
210 "No entry for principal "
211 "'%s' exists in keytab",
212 whoami, kuser);
213 } else {
214 if (debug)
215 __pam_log(LOG_AUTH | LOG_DEBUG,
216 "PAM-KRB5 (%s): "
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);
222 if (debug)
223 __pam_log(LOG_AUTH | LOG_DEBUG,
224 "PAM-KRB5 (%s): "
225 "keytab entry for '%s' found",
226 whoami, user);
227 retval = 1;
230 (void) krb5_kt_close(kcontext, kt_handle);
231 out:
232 if (princ && kcontext)
233 krb5_free_principal(kcontext, princ);
235 if (kcontext)
236 krb5_free_context(kcontext);
238 return (retval);