xref: /illumos-gate/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.c (revision b1d7ec75953cd517f5b7c3d9cb427ff8ec5d7d07)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 /*
26  * Copyright 1990 by the Massachusetts Institute of Technology.
27  * All Rights Reserved.
28  *
29  * Export of this software from the United States of America may
30  *   require a specific license from the United States Government.
31  *   It is the responsibility of any person or organization contemplating
32  *   export to obtain such a license before exporting.
33  *
34  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
35  * distribute this software and its documentation for any purpose and
36  * without fee is hereby granted, provided that the above copyright
37  * notice appear in all copies and that both that copyright notice and
38  * this permission notice appear in supporting documentation, and that
39  * the name of M.I.T. not be used in advertising or publicity pertaining
40  * to distribution of the software without specific, written prior
41  * permission.  Furthermore if you modify this software you must label
42  * your software as modified software and not distribute it in such a
43  * fashion that it might be confused with the original M.I.T. software.
44  * M.I.T. makes no representations about the suitability of
45  * this software for any purpose.  It is provided "as is" without express
46  * or implied warranty.
47  *
48  *
49  * Initialize a credentials cache.
50  */
51 #include <kerberosv5/krb5.h>
52 #include <kerberosv5/com_err.h>
53 #include <assert.h>
54 #include <stdio.h>
55 #include <syslog.h>
56 #include <errno.h>
57 
58 #include <smbsrv/libsmbns.h>
59 #include <smbns_krb.h>
60 
61 int
62 smb_kinit(char *principal_name, char *principal_passwd)
63 {
64 	krb5_context ctx = NULL;
65 	krb5_ccache cc = NULL;
66 	krb5_principal me = NULL;
67 	krb5_creds my_creds;
68 	krb5_error_code code;
69 	const char *errmsg = NULL;
70 	const char *doing = NULL;
71 
72 	assert(principal_name != NULL);
73 	assert(principal_passwd != NULL);
74 
75 	(void) memset(&my_creds, 0, sizeof (my_creds));
76 
77 	/*
78 	 * From this point on, we can goto cleanup because the key variables
79 	 * are initialized.
80 	 */
81 
82 	code = krb5_init_context(&ctx);
83 	if (code) {
84 		doing = "smbns_krb: initializing context";
85 		goto cleanup;
86 	}
87 
88 	code = krb5_cc_default(ctx, &cc);
89 	if (code != 0) {
90 		doing = "smbns_krb: resolve default credentials cache";
91 		goto cleanup;
92 	}
93 
94 	/* Use specified name */
95 	code = krb5_parse_name(ctx, principal_name, &me);
96 	if (code != 0) {
97 		doing = "smbns_krb: parsing principal name";
98 		goto cleanup;
99 	}
100 
101 	code = krb5_get_init_creds_password(ctx, &my_creds, me,
102 	    principal_passwd, NULL, 0, (krb5_deltat)0,
103 	    NULL, NULL);
104 	if (code != 0) {
105 		doing = "smbns_krb: getting initial credentials";
106 
107 		if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
108 			errmsg = "smbns_krb: Password incorrect";
109 		}
110 
111 		goto cleanup;
112 	}
113 
114 	code = krb5_cc_initialize(ctx, cc, me);
115 	if (code != 0) {
116 		doing = "smbns_krb: initializing cache";
117 		goto cleanup;
118 	}
119 
120 	code = krb5_cc_store_cred(ctx, cc, &my_creds);
121 	if (code != 0) {
122 		doing = "smbns_krb: storing credentials";
123 		goto cleanup;
124 	}
125 
126 	/* SUCCESS! */
127 
128 cleanup:
129 	if (code != 0) {
130 		if (errmsg == NULL)
131 			smb_krb5_log_errmsg(ctx, doing, code);
132 		else
133 			syslog(LOG_ERR, "%s (%s)", doing, errmsg);
134 	}
135 
136 	if (my_creds.client == me) {
137 		my_creds.client = NULL;
138 	}
139 	krb5_free_cred_contents(ctx, &my_creds);
140 
141 	if (me)
142 		krb5_free_principal(ctx, me);
143 	if (cc)
144 		(void) krb5_cc_close(ctx, cc);
145 	if (ctx)
146 		krb5_free_context(ctx);
147 
148 	return (code == 0);
149 }
150 
151 /*
152  * Invoke krb5_get_error_message() to generate a richer error message.
153  */
154 void
155 smb_krb5_log_errmsg(krb5_context ctx, const char *prefix, krb5_error_code code)
156 {
157 	const char *msg;
158 
159 	msg = krb5_get_error_message(ctx, code);
160 	syslog(LOG_ERR, "%s (%s)", prefix, msg);
161 	krb5_free_error_message(ctx, msg);
162 }
163 
164 /*
165  * smb_ccache_init
166  *
167  * Creates the directory where the Kerberos ccache file is located
168  * and set KRB5CCNAME in the environment.
169  *
170  * Returns 0 upon succcess.  Otherwise, returns
171  * -1 if it fails to create the specified directory fails.
172  * -2 if it fails to set the KRB5CCNAME environment variable.
173  */
174 int
175 smb_ccache_init(char *dir, char *filename)
176 {
177 	static char buf[MAXPATHLEN];
178 
179 	if ((mkdir(dir, 0700) < 0) && (errno != EEXIST))
180 		return (-1);
181 
182 	(void) snprintf(buf, MAXPATHLEN, "KRB5CCNAME=%s/%s", dir, filename);
183 	if (putenv(buf) != 0)
184 		return (-2);
185 	return (0);
186 }
187 
188 void
189 smb_ccache_remove(char *path)
190 {
191 	if ((remove(path) < 0) && (errno != ENOENT))
192 		syslog(LOG_ERR, "smbns_krb: failed to remove ccache (%s)",
193 		    path);
194 }
195