8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / gss_mechs / mech_krb5 / krb5 / os / kuserok.c
blobca80a0fc0cf1f17eb9fd01b21591b056ff4b47cf
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 * Copyright (c) 2016 by Delphix. All rights reserved.
5 */
8 /*
9 * lib/krb5/os/kuserok.c
11 * Copyright 1990,1993 by the Massachusetts Institute of Technology.
12 * All Rights Reserved.
14 * Export of this software from the United States of America may
15 * require a specific license from the United States Government.
16 * It is the responsibility of any person or organization contemplating
17 * export to obtain such a license before exporting.
19 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
20 * distribute this software and its documentation for any purpose and
21 * without fee is hereby granted, provided that the above copyright
22 * notice appear in all copies and that both that copyright notice and
23 * this permission notice appear in supporting documentation, and that
24 * the name of M.I.T. not be used in advertising or publicity pertaining
25 * to distribution of the software without specific, written prior
26 * permission. Furthermore if you modify this software you must label
27 * your software as modified software and not distribute it in such a
28 * fashion that it might be confused with the original M.I.T. software.
29 * M.I.T. makes no representations about the suitability of
30 * this software for any purpose. It is provided "as is" without express
31 * or implied warranty.
34 * krb5_kuserok()
37 #include "k5-int.h"
38 #if !defined(_WIN32) /* Not yet for Windows */
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <pwd.h>
43 #include <libintl.h>
44 #include <gssapi/gssapi.h>
45 #include <gssapi/gssapi_ext.h>
46 #include <gssapi_krb5.h>
47 #include <gssapiP_krb5.h>
48 #include <syslog.h>
50 #if defined(_AIX) && defined(_IBMR2)
51 #include <sys/access.h>
52 /* xlc has a bug with "const" */
53 #define getpwnam(user) getpwnam((char *)user)
54 #endif
56 #define MAX_USERNAME 65
57 #define CACHE_FILENAME_LEN 35
59 #if defined(__APPLE__) && defined(__MACH__)
60 #include <hfs/hfs_mount.h> /* XXX */
61 #define FILE_OWNER_OK(UID) ((UID) == 0 || (UID) == UNKNOWNUID)
62 #else
63 #define FILE_OWNER_OK(UID) ((UID) == 0)
64 #endif
66 /* Solaris Kerberos */
67 extern void
68 gsscred_set_options();
70 extern OM_uint32
71 gsscred_name_to_unix_cred_ext();
73 extern int
74 safechown(const char *src, uid_t uid, gid_t gid, int mode);
76 extern const char *error_message(long);
79 krb5_data tgtname = {
81 KRB5_TGS_NAME_SIZE,
82 KRB5_TGS_NAME
85 /* Solaris Kerberos */
86 static krb5_error_code
87 krb5_move_ccache(krb5_context kcontext, krb5_principal client,
88 struct passwd *pwd)
90 char *name = 0;
91 static char ccache_name_buf[CACHE_FILENAME_LEN];
92 krb5_ccache ccache = NULL;
93 krb5_error_code retval;
95 name = getenv(KRB5_ENV_CCNAME);
96 if (name == 0)
98 * This means that there was no forwarding
99 * of creds
101 return (0);
102 else {
104 * creds have been forwarded and stored in
105 * KRB5_ENV_CCNAME and now we need to store it
106 * under uid
109 krb5_creds mcreds, save_v5creds;
111 memset(&mcreds, 0, sizeof (mcreds));
112 memset(&save_v5creds, 0, sizeof (save_v5creds));
114 mcreds.client = client;
115 retval = krb5_build_principal_ext(kcontext, &mcreds.server,
116 krb5_princ_realm(kcontext, client)->length,
117 krb5_princ_realm(kcontext, client)->data,
118 tgtname.length, tgtname.data,
119 krb5_princ_realm(kcontext, client)->length,
120 krb5_princ_realm(kcontext, client)->data,
122 if (retval) {
123 syslog(LOG_ERR,
124 gettext("KRB5: %s while creating"
125 "V5 krbtgt principal "),
126 error_message(retval));
127 return (retval);
130 mcreds.ticket_flags = 0;
131 retval = krb5_cc_default(kcontext, &ccache);
132 if (retval) {
133 syslog(LOG_ERR,
134 gettext("KRB5: %s while getting "
135 "default cache "),
136 error_message(retval));
137 return (retval);
140 retval = krb5_cc_retrieve_cred(kcontext, ccache,
142 &mcreds, &save_v5creds);
143 if (retval) {
144 syslog(LOG_ERR,
145 gettext("KRB5: %s while retrieving "
146 "cerdentials "),
147 error_message(retval));
148 return (retval);
151 * reset the env variable and recreate the
152 * cache using the default cache name
154 retval = krb5_cc_destroy(kcontext, ccache);
155 if (retval) {
156 syslog(LOG_ERR,
157 gettext("KRB5: %s while destroying cache "),
158 error_message(retval));
159 return (retval);
161 krb5_unsetenv(KRB5_ENV_CCNAME);
162 snprintf(ccache_name_buf,
163 CACHE_FILENAME_LEN,
164 "FILE:/tmp/krb5cc_%d", pwd->pw_uid);
165 krb5_setenv(KRB5_ENV_CCNAME, ccache_name_buf, 1);
166 retval = krb5_cc_resolve(kcontext, ccache_name_buf, &ccache);
167 if (retval) {
168 syslog(LOG_ERR,
169 gettext("KRB5: %s while resolving cache "),
170 error_message(retval));
171 return (retval);
173 retval = krb5_cc_initialize(kcontext, ccache, client);
174 if (retval) {
175 syslog(LOG_ERR,
176 gettext("KRB5: %s while initializing cache "),
177 error_message(retval));
178 return (retval);
180 retval = krb5_cc_store_cred(kcontext, ccache, &save_v5creds);
181 if (retval) {
182 syslog(LOG_ERR,
183 gettext("KRB5: %s while storing creds "),
184 error_message(retval));
185 return (retval);
187 snprintf(ccache_name_buf,
188 CACHE_FILENAME_LEN,
189 "/tmp/krb5cc_%d", pwd->pw_uid);
190 if (safechown(ccache_name_buf, pwd->pw_uid,
191 pwd->pw_gid, -1) == -1) {
192 syslog(LOG_ERR,
193 gettext("KRB5: Can not change "
194 "ownership of cache file, "
195 "possible security breach\n"));
199 return (0);
204 * Solaris Kerberos:
205 * krb5_gsscred: Given a kerberos principal try to find the corresponding
206 * local uid via the gss cred table. Return TRUE if the uid was found in the
207 * cred table, otherwise return FALSE.
209 static krb5_boolean
210 krb5_gsscred(krb5_principal principal, uid_t *uid)
212 OM_uint32 minor, major;
213 gss_name_t name;
214 gss_buffer_desc name_buf;
216 name_buf.value = &principal;
217 name_buf.length = sizeof (principal);
220 * Convert the kerb principal in to a gss name
222 major = gss_import_name(&minor, &name_buf,
223 (gss_OID)gss_nt_krb5_principal, &name);
225 if (major != GSS_S_COMPLETE)
226 return (FALSE);
228 gsscred_set_options();
231 * Get the uid mapping from the gsscred table.
232 * (but set flag to not call back into this mech as we do krb5
233 * auth_to_local name mapping from this module).
235 major = gsscred_name_to_unix_cred_ext(name, (gss_OID)gss_mech_krb5,
236 uid, 0, 0, 0, 0);
238 (void) gss_release_name(&minor, &name);
240 if (major != GSS_S_COMPLETE)
241 return (FALSE);
243 return (TRUE);
247 * Given a Kerberos principal "principal", and a local username "luser",
248 * determine whether user is authorized to login according to the
249 * authorization file ("~luser/.k5login" by default). Returns TRUE
250 * if authorized, FALSE if not authorized.
252 * If there is no account for "luser" on the local machine, returns
253 * FALSE. If there is no authorization file, and the given Kerberos
254 * name "server" translates to the same name as "luser" (using
255 * krb5_aname_to_lname()), returns TRUE. Otherwise, if the authorization file
256 * can't be accessed, returns FALSE. Otherwise, the file is read for
257 * a matching principal name, instance, and realm. If one is found,
258 * returns TRUE, if none is found, returns FALSE.
260 * The file entries are in the format produced by krb5_unparse_name(),
261 * one entry per line.
265 krb5_boolean KRB5_CALLCONV
266 krb5_kuserok(krb5_context context, krb5_principal principal, const char *luser)
268 struct stat sbuf;
269 struct passwd *pwd;
270 char pbuf[MAXPATHLEN];
271 krb5_boolean isok = FALSE;
272 FILE *fp;
273 char kuser[MAX_USERNAME];
274 char *princname;
275 char linebuf[BUFSIZ];
276 char *newline;
277 /* Solaris Kerberos */
278 uid_t uid;
279 int gobble;
281 /* no account => no access */
282 char pwbuf[BUFSIZ];
283 struct passwd pwx;
284 if (k5_getpwnam_r(luser, &pwx, pwbuf, sizeof(pwbuf), &pwd) != 0)
285 return(FALSE);
286 (void) strncpy(pbuf, pwd->pw_dir, sizeof(pbuf) - 1);
287 pbuf[sizeof(pbuf) - 1] = '\0';
288 (void) strncat(pbuf, "/.k5login", sizeof(pbuf) - 1 - strlen(pbuf));
290 if (access(pbuf, F_OK)) { /* not accessible */
292 * if they're trying to log in as themself, and there is no .k5login file,
293 * let them. First, have krb5 check it's rules. If no success,
294 * search the gsscred table (the sequence here should be consistent
295 * with the uid mappings done for gssd).
297 if (!(krb5_aname_to_localname(context, principal,
298 sizeof(kuser), kuser))
299 && (strcmp(kuser, luser) == 0)) {
300 /* Solaris Kerberos */
301 if (krb5_move_ccache(context, principal, pwd))
302 return (FALSE);
303 return(TRUE);
306 if (krb5_gsscred(principal, &uid)) {
307 #ifdef DEBUG
308 char *princname;
310 (void)krb5_unparse_name(context, principal, &princname);
311 syslog(LOG_DEBUG, "gsscred mapped %s to %d expecting %d (%s)\n",
312 princname, uid, pwd->pw_uid, luser);
313 free(princname);
314 #endif
315 if (uid == pwd->pw_uid) {
316 if (krb5_move_ccache(context, principal, pwd))
317 return (FALSE);
318 return (TRUE);
323 if (krb5_unparse_name(context, principal, &princname))
324 return(FALSE); /* no hope of matching */
326 /* open ~/.k5login */
327 /* Solaris Kerberos */
328 if ((fp = fopen(pbuf, "rF")) == NULL) {
329 free(princname);
330 return(FALSE);
333 * For security reasons, the .k5login file must be owned either by
334 * the user himself, or by root. Otherwise, don't grant access.
336 if (fstat(fileno(fp), &sbuf)) {
337 fclose(fp);
338 free(princname);
339 return(FALSE);
341 if (sbuf.st_uid != pwd->pw_uid && !FILE_OWNER_OK(sbuf.st_uid)) {
342 fclose(fp);
343 free(princname);
344 return(FALSE);
347 /* check each line */
348 while (!isok && (fgets(linebuf, BUFSIZ, fp) != NULL)) {
349 /* null-terminate the input string */
350 linebuf[BUFSIZ-1] = '\0';
351 newline = NULL;
352 /* nuke the newline if it exists */
353 if ((newline = strchr(linebuf, '\n')))
354 *newline = '\0';
355 if (!strcmp(linebuf, princname)) {
356 isok = TRUE;
357 /* Solaris Kerberos */
358 if (krb5_move_ccache(context, principal, pwd))
359 return (FALSE);
360 continue;
362 /* clean up the rest of the line if necessary */
363 if (!newline)
364 while (((gobble = getc(fp)) != EOF) && gobble != '\n');
366 free(princname);
367 fclose(fp);
368 return(isok);
371 /* Solaris Kerberos */
372 OM_uint32
373 krb5_gss_userok(OM_uint32 *minor,
374 const gss_name_t pname,
375 const char *user,
376 int *user_ok)
378 krb5_context ctxt;
379 OM_uint32 kret;
381 if (pname == NULL || user == NULL)
382 return (GSS_S_CALL_INACCESSIBLE_READ);
384 if (minor == NULL || user_ok == NULL)
385 return (GSS_S_CALL_INACCESSIBLE_WRITE);
387 *user_ok = 0;
389 kret = krb5_gss_init_context(&ctxt);
390 if (kret) {
391 *minor = kret;
392 return (GSS_S_FAILURE);
395 if (! kg_validate_name(pname)) {
396 *minor = (OM_uint32) G_VALIDATE_FAILED;
397 krb5_free_context(ctxt);
398 return (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
401 if (krb5_kuserok(ctxt, (krb5_principal) pname, user)) {
402 *user_ok = 1;
405 krb5_free_context(ctxt);
406 return (GSS_S_COMPLETE);
409 #else /* _WIN32 */
412 * If the given Kerberos name "server" translates to the same name as "luser"
413 * (using * krb5_aname_to_lname()), returns TRUE.
415 krb5_boolean KRB5_CALLCONV
416 krb5_kuserok(context, principal, luser)
417 krb5_context context;
418 krb5_principal principal;
419 const char *luser;
421 char kuser[50];
423 if (krb5_aname_to_localname(context, principal, sizeof(kuser), kuser))
424 return FALSE;
426 if (strcmp(kuser, luser) == 0)
427 return TRUE;
429 return FALSE;
431 #endif /* _WIN32 */