xref: /titanic_44/usr/src/lib/smbsrv/libsmbns/common/smbns_ksetpwd.c (revision 148c5f43199ca0b43fc8e3b643aab11cd66ea327)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw 
22da6c28aaSamw /*
23*148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #include <stdio.h>
27da6c28aaSamw #include <stdlib.h>
28da6c28aaSamw #include <string.h>
29da6c28aaSamw #include <strings.h>
30da6c28aaSamw #include <unistd.h>
31da6c28aaSamw #include <ctype.h>
32da6c28aaSamw #include <errno.h>
33da6c28aaSamw #include <syslog.h>
34faa1795aSjb150015 #include <netdb.h>
35faa1795aSjb150015 #include <sys/param.h>
36da6c28aaSamw #include <kerberosv5/krb5.h>
3755bf511dSas200622 #include <kerberosv5/com_err.h>
38faa1795aSjb150015 
39faa1795aSjb150015 #include <smbsrv/libsmb.h>
4055bf511dSas200622 #include <smbns_krb.h>
41da6c28aaSamw 
42faa1795aSjb150015 /*
43*148c5f43SAlan Wright  * Kerberized services available on the system.
44faa1795aSjb150015  */
45*148c5f43SAlan Wright static smb_krb5_pn_t smb_krb5_pn_tab[] = {
46faa1795aSjb150015 	/*
47*148c5f43SAlan Wright 	 * Service keys are salted with the SMB_KRB_PN_ID_ID_SALT prinipal
48*148c5f43SAlan Wright 	 * name.
49faa1795aSjb150015 	 */
50*148c5f43SAlan Wright 	{SMB_KRB5_PN_ID_SALT,		SMB_PN_SVC_HOST,	SMB_PN_SALT},
51faa1795aSjb150015 
52*148c5f43SAlan Wright 	/* HOST */
53*148c5f43SAlan Wright 	{SMB_KRB5_PN_ID_HOST_FQHN,	SMB_PN_SVC_HOST,
54*148c5f43SAlan Wright 	    SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR | SMB_PN_UPN_ATTR},
55faa1795aSjb150015 
56*148c5f43SAlan Wright 	/* NFS */
57*148c5f43SAlan Wright 	{SMB_KRB5_PN_ID_NFS_FQHN,	SMB_PN_SVC_NFS,
58*148c5f43SAlan Wright 	    SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR},
59faa1795aSjb150015 
60*148c5f43SAlan Wright 	/* HTTP */
61*148c5f43SAlan Wright 	{SMB_KRB5_PN_ID_HTTP_FQHN,	SMB_PN_SVC_HTTP,
62*148c5f43SAlan Wright 	    SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR},
63faa1795aSjb150015 
64*148c5f43SAlan Wright 	/* ROOT */
65*148c5f43SAlan Wright 	{SMB_KRB5_PN_ID_ROOT_FQHN,	SMB_PN_SVC_ROOT,
66*148c5f43SAlan Wright 	    SMB_PN_KEYTAB_ENTRY | SMB_PN_SPN_ATTR},
67*148c5f43SAlan Wright };
68faa1795aSjb150015 
69*148c5f43SAlan Wright #define	SMB_KRB5_SPN_TAB_SZ \
70*148c5f43SAlan Wright 	(sizeof (smb_krb5_pn_tab) / sizeof (smb_krb5_pn_tab[0]))
71faa1795aSjb150015 
72*148c5f43SAlan Wright #define	SMB_KRB5_MAX_BUFLEN	128
73*148c5f43SAlan Wright 
74*148c5f43SAlan Wright static int smb_krb5_kt_open(krb5_context, char *, krb5_keytab *);
75*148c5f43SAlan Wright static int smb_krb5_kt_addkey(krb5_context, krb5_keytab, const krb5_principal,
76*148c5f43SAlan Wright     krb5_enctype, krb5_kvno, const krb5_data *, const char *);
77*148c5f43SAlan Wright static int smb_krb5_spn_count(uint32_t);
78*148c5f43SAlan Wright static smb_krb5_pn_t *smb_krb5_lookup_pn(smb_krb5_pn_id_t);
79*148c5f43SAlan Wright static char *smb_krb5_get_pn_by_id(smb_krb5_pn_id_t, uint32_t,
80*148c5f43SAlan Wright     const char *);
81*148c5f43SAlan Wright static int smb_krb5_get_kprinc(krb5_context, smb_krb5_pn_id_t, uint32_t,
82*148c5f43SAlan Wright     const char *, krb5_principal *);
83*148c5f43SAlan Wright 
84faa1795aSjb150015 
85faa1795aSjb150015 /*
86*148c5f43SAlan Wright  * Generates a null-terminated array of principal names that
87*148c5f43SAlan Wright  * represents the list of the available Kerberized services
88*148c5f43SAlan Wright  * of the specified type (SPN attribute, UPN attribute, or
89*148c5f43SAlan Wright  * keytab entry).
90faa1795aSjb150015  *
91*148c5f43SAlan Wright  * Returns the number of principal names returned via the 1st
92*148c5f43SAlan Wright  * output parameter (i.e. vals).
93*148c5f43SAlan Wright  *
94*148c5f43SAlan Wright  * Caller must invoke smb_krb5_free_spns to free the allocated
95*148c5f43SAlan Wright  * memory when finished.
96faa1795aSjb150015  */
97*148c5f43SAlan Wright uint32_t
smb_krb5_get_pn_set(smb_krb5_pn_set_t * set,uint32_t type,char * fqdn)98*148c5f43SAlan Wright smb_krb5_get_pn_set(smb_krb5_pn_set_t *set, uint32_t type, char *fqdn)
99faa1795aSjb150015 {
100*148c5f43SAlan Wright 	int cnt, i;
101*148c5f43SAlan Wright 	smb_krb5_pn_t *tabent;
102faa1795aSjb150015 
103*148c5f43SAlan Wright 	if (!set || !fqdn)
104*148c5f43SAlan Wright 		return (0);
105faa1795aSjb150015 
106*148c5f43SAlan Wright 	bzero(set, sizeof (smb_krb5_pn_set_t));
107*148c5f43SAlan Wright 	cnt = smb_krb5_spn_count(type);
108*148c5f43SAlan Wright 	set->s_pns = (char **)calloc(cnt + 1, sizeof (char *));
109faa1795aSjb150015 
110*148c5f43SAlan Wright 	if (set->s_pns == NULL)
111*148c5f43SAlan Wright 		return (0);
112faa1795aSjb150015 
113*148c5f43SAlan Wright 	for (i = 0, set->s_cnt = 0; i < SMB_KRB5_SPN_TAB_SZ; i++) {
114*148c5f43SAlan Wright 		tabent = &smb_krb5_pn_tab[i];
115*148c5f43SAlan Wright 
116*148c5f43SAlan Wright 		if (set->s_cnt == cnt)
117*148c5f43SAlan Wright 			break;
118*148c5f43SAlan Wright 
119*148c5f43SAlan Wright 		if ((tabent->p_flags & type) != type)
120*148c5f43SAlan Wright 			continue;
121*148c5f43SAlan Wright 
122*148c5f43SAlan Wright 		set->s_pns[set->s_cnt] = smb_krb5_get_pn_by_id(tabent->p_id,
123*148c5f43SAlan Wright 		    type, fqdn);
124*148c5f43SAlan Wright 		if (set->s_pns[set->s_cnt] == NULL) {
125*148c5f43SAlan Wright 			syslog(LOG_ERR, "smbns_ksetpwd: failed to obtain "
126*148c5f43SAlan Wright 			    "principal names: possible transient memory "
127*148c5f43SAlan Wright 			    "shortage");
128*148c5f43SAlan Wright 			smb_krb5_free_pn_set(set);
129*148c5f43SAlan Wright 			return (0);
130faa1795aSjb150015 		}
131faa1795aSjb150015 
132*148c5f43SAlan Wright 		set->s_cnt++;
133*148c5f43SAlan Wright 	}
134faa1795aSjb150015 
135*148c5f43SAlan Wright 	if (set->s_cnt == 0)
136*148c5f43SAlan Wright 		smb_krb5_free_pn_set(set);
137*148c5f43SAlan Wright 
138*148c5f43SAlan Wright 	return (set->s_cnt);
139*148c5f43SAlan Wright }
140*148c5f43SAlan Wright 
141*148c5f43SAlan Wright void
smb_krb5_free_pn_set(smb_krb5_pn_set_t * set)142*148c5f43SAlan Wright smb_krb5_free_pn_set(smb_krb5_pn_set_t *set)
143*148c5f43SAlan Wright {
144*148c5f43SAlan Wright 	int i;
145*148c5f43SAlan Wright 
146*148c5f43SAlan Wright 	if (set == NULL || set->s_pns == NULL)
147*148c5f43SAlan Wright 		return;
148*148c5f43SAlan Wright 
149*148c5f43SAlan Wright 	for (i = 0; i < set->s_cnt; i++)
150*148c5f43SAlan Wright 		free(set->s_pns[i]);
151*148c5f43SAlan Wright 
152*148c5f43SAlan Wright 	free(set->s_pns);
153*148c5f43SAlan Wright 	set->s_pns = NULL;
154faa1795aSjb150015 }
155da6c28aaSamw 
156da6c28aaSamw /*
157da6c28aaSamw  * Initialize the kerberos context.
158da6c28aaSamw  * Return 0 on success. Otherwise, return -1.
159da6c28aaSamw  */
160da6c28aaSamw int
smb_krb5_ctx_init(krb5_context * ctx)161da6c28aaSamw smb_krb5_ctx_init(krb5_context *ctx)
162da6c28aaSamw {
163da6c28aaSamw 	if (krb5_init_context(ctx) != 0)
164da6c28aaSamw 		return (-1);
165da6c28aaSamw 
166da6c28aaSamw 	return (0);
167da6c28aaSamw }
168da6c28aaSamw 
169da6c28aaSamw /*
170da6c28aaSamw  * Free the kerberos context.
171da6c28aaSamw  */
172da6c28aaSamw void
smb_krb5_ctx_fini(krb5_context ctx)173da6c28aaSamw smb_krb5_ctx_fini(krb5_context ctx)
174da6c28aaSamw {
175da6c28aaSamw 	krb5_free_context(ctx);
176da6c28aaSamw }
177da6c28aaSamw 
178da6c28aaSamw /*
179*148c5f43SAlan Wright  * Create an array of Kerberos Princiapls given an array of principal names.
180*148c5f43SAlan Wright  * Caller must free the allocated memory using smb_krb5_free_kprincs()
181*148c5f43SAlan Wright  * upon success.
182da6c28aaSamw  *
183*148c5f43SAlan Wright  * Returns 0 on success. Otherwise, returns -1.
184*148c5f43SAlan Wright  */
185*148c5f43SAlan Wright int
smb_krb5_get_kprincs(krb5_context ctx,char ** names,size_t num,krb5_principal ** krb5princs)186*148c5f43SAlan Wright smb_krb5_get_kprincs(krb5_context ctx, char **names, size_t num,
187*148c5f43SAlan Wright     krb5_principal **krb5princs)
188*148c5f43SAlan Wright {
189*148c5f43SAlan Wright 	int i;
190*148c5f43SAlan Wright 
191*148c5f43SAlan Wright 	if ((*krb5princs = calloc(num, sizeof (krb5_principal *))) == NULL) {
192*148c5f43SAlan Wright 		return (-1);
193*148c5f43SAlan Wright 	}
194*148c5f43SAlan Wright 
195*148c5f43SAlan Wright 	for (i = 0; i < num; i++) {
196*148c5f43SAlan Wright 		if (krb5_parse_name(ctx, names[i], &(*krb5princs)[i]) != 0) {
197*148c5f43SAlan Wright 			smb_krb5_free_kprincs(ctx, *krb5princs, i);
198*148c5f43SAlan Wright 			return (-1);
199*148c5f43SAlan Wright 		}
200*148c5f43SAlan Wright 	}
201*148c5f43SAlan Wright 
202*148c5f43SAlan Wright 	return (0);
203*148c5f43SAlan Wright }
204*148c5f43SAlan Wright 
205*148c5f43SAlan Wright void
smb_krb5_free_kprincs(krb5_context ctx,krb5_principal * krb5princs,size_t num)206*148c5f43SAlan Wright smb_krb5_free_kprincs(krb5_context ctx, krb5_principal *krb5princs,
207*148c5f43SAlan Wright     size_t num)
208*148c5f43SAlan Wright {
209*148c5f43SAlan Wright 	int i;
210*148c5f43SAlan Wright 
211*148c5f43SAlan Wright 	for (i = 0; i < num; i++)
212*148c5f43SAlan Wright 		krb5_free_principal(ctx, krb5princs[i]);
213*148c5f43SAlan Wright 
214*148c5f43SAlan Wright 	free(krb5princs);
215*148c5f43SAlan Wright }
216*148c5f43SAlan Wright 
217*148c5f43SAlan Wright /*
218da6c28aaSamw  * Set the workstation trust account password.
219da6c28aaSamw  * Returns 0 on success.  Otherwise, returns non-zero value.
220da6c28aaSamw  */
221da6c28aaSamw int
smb_krb5_setpwd(krb5_context ctx,const char * fqdn,char * passwd)222*148c5f43SAlan Wright smb_krb5_setpwd(krb5_context ctx, const char *fqdn, char *passwd)
223da6c28aaSamw {
224da6c28aaSamw 	krb5_error_code code;
225da6c28aaSamw 	krb5_ccache cc = NULL;
226*148c5f43SAlan Wright 	int result_code = 0;
227da6c28aaSamw 	krb5_data result_code_string, result_string;
228*148c5f43SAlan Wright 	krb5_principal princ;
229*148c5f43SAlan Wright 	char msg[SMB_KRB5_MAX_BUFLEN];
230*148c5f43SAlan Wright 
231*148c5f43SAlan Wright 	if (smb_krb5_get_kprinc(ctx, SMB_KRB5_PN_ID_HOST_FQHN,
232*148c5f43SAlan Wright 	    SMB_PN_UPN_ATTR, fqdn, &princ) != 0)
233*148c5f43SAlan Wright 		return (-1);
234da6c28aaSamw 
235da6c28aaSamw 	(void) memset(&result_code_string, 0, sizeof (result_code_string));
236da6c28aaSamw 	(void) memset(&result_string, 0, sizeof (result_string));
237da6c28aaSamw 
238da6c28aaSamw 	if ((code = krb5_cc_default(ctx, &cc)) != 0) {
239*148c5f43SAlan Wright 		(void) snprintf(msg, sizeof (msg), "smbns_ksetpwd: failed to "
240*148c5f43SAlan Wright 		    "find %s", SMB_CCACHE_PATH);
241*148c5f43SAlan Wright 		smb_krb5_log_errmsg(ctx, msg, code);
242*148c5f43SAlan Wright 		krb5_free_principal(ctx, princ);
243da6c28aaSamw 		return (-1);
244da6c28aaSamw 	}
245da6c28aaSamw 
246da6c28aaSamw 	code = krb5_set_password_using_ccache(ctx, cc, passwd, princ,
247da6c28aaSamw 	    &result_code, &result_code_string, &result_string);
248da6c28aaSamw 
249*148c5f43SAlan Wright 	if (code != 0)
250*148c5f43SAlan Wright 		smb_krb5_log_errmsg(ctx, "smbns_ksetpwd: KPASSWD protocol "
251*148c5f43SAlan Wright 		    "exchange failed", code);
252*148c5f43SAlan Wright 
2535ad42b1bSSurya Prakki 	(void) krb5_cc_close(ctx, cc);
254da6c28aaSamw 
255*148c5f43SAlan Wright 	if (result_code != 0)
256*148c5f43SAlan Wright 		syslog(LOG_ERR, "smbns_ksetpwd: KPASSWD failed: %s",
257*148c5f43SAlan Wright 		    result_code_string.data);
258cbfb650aScp160787 
259*148c5f43SAlan Wright 	krb5_free_principal(ctx, princ);
260cbfb650aScp160787 	free(result_code_string.data);
261cbfb650aScp160787 	free(result_string.data);
262da6c28aaSamw 	return (code);
263da6c28aaSamw }
264da6c28aaSamw 
265da6c28aaSamw /*
26655bf511dSas200622  * Open the keytab file for writing.
26755bf511dSas200622  * The keytab should be closed by calling krb5_kt_close().
268da6c28aaSamw  */
26955bf511dSas200622 static int
smb_krb5_kt_open(krb5_context ctx,char * fname,krb5_keytab * kt)270*148c5f43SAlan Wright smb_krb5_kt_open(krb5_context ctx, char *fname, krb5_keytab *kt)
271da6c28aaSamw {
272da6c28aaSamw 	char *ktname;
273*148c5f43SAlan Wright 	krb5_error_code code;
27455bf511dSas200622 	int len;
275*148c5f43SAlan Wright 	char msg[SMB_KRB5_MAX_BUFLEN];
276da6c28aaSamw 
27755bf511dSas200622 	*kt = NULL;
278da6c28aaSamw 	len = snprintf(NULL, 0, "WRFILE:%s", fname) + 1;
279da6c28aaSamw 	if ((ktname = malloc(len)) == NULL) {
280*148c5f43SAlan Wright 		syslog(LOG_ERR, "smbns_ksetpwd: unable to open keytab %s: "
281*148c5f43SAlan Wright 		    "possible transient memory shortage", fname);
282da6c28aaSamw 		return (-1);
283da6c28aaSamw 	}
284da6c28aaSamw 
285da6c28aaSamw 	(void) snprintf(ktname, len, "WRFILE:%s", fname);
286da6c28aaSamw 
287*148c5f43SAlan Wright 	if ((code = krb5_kt_resolve(ctx, ktname, kt)) != 0) {
288*148c5f43SAlan Wright 		(void) snprintf(msg, sizeof (msg), "smbns_ksetpwd: %s", fname);
289*148c5f43SAlan Wright 		smb_krb5_log_errmsg(ctx, msg, code);
290da6c28aaSamw 		free(ktname);
291da6c28aaSamw 		return (-1);
292da6c28aaSamw 	}
293da6c28aaSamw 
294da6c28aaSamw 	free(ktname);
29555bf511dSas200622 	return (0);
29655bf511dSas200622 }
29755bf511dSas200622 
29855bf511dSas200622 /*
299*148c5f43SAlan Wright  * Populate the keytab with keys of the specified key version for the
300*148c5f43SAlan Wright  * specified set of krb5 principals.  All service keys will be salted by:
301*148c5f43SAlan Wright  * host/<truncated@15_lower_case_hostname>.<fqdn>@<REALM>
30255bf511dSas200622  */
30355bf511dSas200622 int
smb_krb5_kt_populate(krb5_context ctx,const char * fqdn,krb5_principal * princs,int count,char * fname,krb5_kvno kvno,char * passwd,krb5_enctype * enctypes,int enctype_count)304*148c5f43SAlan Wright smb_krb5_kt_populate(krb5_context ctx, const char *fqdn,
305*148c5f43SAlan Wright     krb5_principal *princs, int count, char *fname, krb5_kvno kvno,
306*148c5f43SAlan Wright     char *passwd, krb5_enctype *enctypes, int enctype_count)
30755bf511dSas200622 {
30855bf511dSas200622 	krb5_keytab kt = NULL;
309*148c5f43SAlan Wright 	krb5_data salt;
310*148c5f43SAlan Wright 	krb5_error_code code;
311*148c5f43SAlan Wright 	krb5_principal salt_princ;
312faa1795aSjb150015 	int i, j;
31355bf511dSas200622 
314*148c5f43SAlan Wright 	if (smb_krb5_kt_open(ctx, fname, &kt) != 0)
31555bf511dSas200622 		return (-1);
31655bf511dSas200622 
317*148c5f43SAlan Wright 	if (smb_krb5_get_kprinc(ctx, SMB_KRB5_PN_ID_SALT, SMB_PN_SALT,
318*148c5f43SAlan Wright 	    fqdn, &salt_princ) != 0) {
319*148c5f43SAlan Wright 		(void) krb5_kt_close(ctx, kt);
320*148c5f43SAlan Wright 		return (-1);
321*148c5f43SAlan Wright 	}
322*148c5f43SAlan Wright 
323*148c5f43SAlan Wright 	code = krb5_principal2salt(ctx, salt_princ, &salt);
324*148c5f43SAlan Wright 	if (code != 0) {
325*148c5f43SAlan Wright 		smb_krb5_log_errmsg(ctx, "smbns_ksetpwd: salt computation "
326*148c5f43SAlan Wright 		    "failed", code);
327*148c5f43SAlan Wright 		krb5_free_principal(ctx, salt_princ);
328*148c5f43SAlan Wright 		(void) krb5_kt_close(ctx, kt);
329*148c5f43SAlan Wright 		return (-1);
330*148c5f43SAlan Wright 	}
331*148c5f43SAlan Wright 
332*148c5f43SAlan Wright 	for (j = 0; j < count; j++) {
333da6c28aaSamw 		for (i = 0; i < enctype_count; i++) {
334*148c5f43SAlan Wright 			if (smb_krb5_kt_addkey(ctx, kt, princs[j], enctypes[i],
335*148c5f43SAlan Wright 			    kvno, &salt, passwd) != 0) {
336*148c5f43SAlan Wright 				krb5_free_principal(ctx, salt_princ);
337*148c5f43SAlan Wright 				krb5_xfree(salt.data);
3385ad42b1bSSurya Prakki 				(void) krb5_kt_close(ctx, kt);
339faa1795aSjb150015 				return (-1);
340faa1795aSjb150015 			}
341da6c28aaSamw 		}
342da6c28aaSamw 
343da6c28aaSamw 	}
344*148c5f43SAlan Wright 	krb5_free_principal(ctx, salt_princ);
345*148c5f43SAlan Wright 	krb5_xfree(salt.data);
3465ad42b1bSSurya Prakki 	(void) krb5_kt_close(ctx, kt);
347faa1795aSjb150015 	return (0);
348faa1795aSjb150015 }
349faa1795aSjb150015 
350faa1795aSjb150015 boolean_t
smb_krb5_kt_find(smb_krb5_pn_id_t id,const char * fqdn,char * fname)351*148c5f43SAlan Wright smb_krb5_kt_find(smb_krb5_pn_id_t id, const char *fqdn, char *fname)
352faa1795aSjb150015 {
353faa1795aSjb150015 	krb5_context ctx;
354faa1795aSjb150015 	krb5_keytab kt;
355faa1795aSjb150015 	krb5_keytab_entry entry;
356faa1795aSjb150015 	krb5_principal princ;
357faa1795aSjb150015 	char ktname[MAXPATHLEN];
358faa1795aSjb150015 	boolean_t found = B_FALSE;
359faa1795aSjb150015 
360*148c5f43SAlan Wright 	if (!fqdn || !fname)
361faa1795aSjb150015 		return (found);
362faa1795aSjb150015 
363*148c5f43SAlan Wright 	if (smb_krb5_ctx_init(&ctx) != 0)
364faa1795aSjb150015 		return (found);
365faa1795aSjb150015 
366*148c5f43SAlan Wright 	if (smb_krb5_get_kprinc(ctx, id, SMB_PN_KEYTAB_ENTRY, fqdn,
367*148c5f43SAlan Wright 	    &princ) != 0) {
368faa1795aSjb150015 		smb_krb5_ctx_fini(ctx);
369faa1795aSjb150015 		return (found);
370faa1795aSjb150015 	}
371faa1795aSjb150015 
372faa1795aSjb150015 	(void) snprintf(ktname, MAXPATHLEN, "FILE:%s", fname);
373faa1795aSjb150015 	if (krb5_kt_resolve(ctx, ktname, &kt) == 0) {
374faa1795aSjb150015 		if (krb5_kt_get_entry(ctx, kt, princ, 0, 0, &entry) == 0) {
375faa1795aSjb150015 			found = B_TRUE;
3765ad42b1bSSurya Prakki 			(void) krb5_kt_free_entry(ctx, &entry);
377faa1795aSjb150015 		}
378da6c28aaSamw 
3795ad42b1bSSurya Prakki 		(void) krb5_kt_close(ctx, kt);
380faa1795aSjb150015 	}
381faa1795aSjb150015 
382faa1795aSjb150015 	krb5_free_principal(ctx, princ);
383faa1795aSjb150015 	smb_krb5_ctx_fini(ctx);
384faa1795aSjb150015 	return (found);
385da6c28aaSamw }
386da6c28aaSamw 
387da6c28aaSamw /*
388*148c5f43SAlan Wright  * Add a key of the specified encryption type for the specified principal
389*148c5f43SAlan Wright  * to the keytab file.
390da6c28aaSamw  * Returns 0 on success. Otherwise, returns -1.
391da6c28aaSamw  */
392da6c28aaSamw static int
smb_krb5_kt_addkey(krb5_context ctx,krb5_keytab kt,const krb5_principal princ,krb5_enctype enctype,krb5_kvno kvno,const krb5_data * salt,const char * pw)393*148c5f43SAlan Wright smb_krb5_kt_addkey(krb5_context ctx, krb5_keytab kt, const krb5_principal princ,
394*148c5f43SAlan Wright     krb5_enctype enctype, krb5_kvno kvno, const krb5_data *salt,
395*148c5f43SAlan Wright     const char *pw)
396da6c28aaSamw {
397da6c28aaSamw 	krb5_keytab_entry *entry;
398*148c5f43SAlan Wright 	krb5_data password;
399da6c28aaSamw 	krb5_keyblock key;
400da6c28aaSamw 	krb5_error_code code;
401*148c5f43SAlan Wright 	char buf[SMB_KRB5_MAX_BUFLEN], msg[SMB_KRB5_MAX_BUFLEN];
402da6c28aaSamw 	int rc = 0;
403da6c28aaSamw 
404da6c28aaSamw 	if ((code = krb5_enctype_to_string(enctype, buf, sizeof (buf)))) {
405*148c5f43SAlan Wright 		(void) snprintf(msg, sizeof (msg), "smbns_ksetpwd: unknown "
406*148c5f43SAlan Wright 		    "encryption type (%d)", enctype);
407*148c5f43SAlan Wright 		smb_krb5_log_errmsg(ctx, msg, code);
408da6c28aaSamw 		return (-1);
409da6c28aaSamw 	}
410da6c28aaSamw 
411da6c28aaSamw 	if ((entry = (krb5_keytab_entry *) malloc(sizeof (*entry))) == NULL) {
412*148c5f43SAlan Wright 		syslog(LOG_ERR, "smbns_ksetpwd: possible transient "
413*148c5f43SAlan Wright 		    "memory shortage");
414da6c28aaSamw 		return (-1);
415da6c28aaSamw 	}
416da6c28aaSamw 
417da6c28aaSamw 	(void) memset((char *)entry, 0, sizeof (*entry));
418da6c28aaSamw 
419da6c28aaSamw 	password.length = strlen(pw);
420da6c28aaSamw 	password.data = (char *)pw;
421da6c28aaSamw 
422*148c5f43SAlan Wright 	code = krb5_c_string_to_key(ctx, enctype, &password, salt, &key);
423da6c28aaSamw 	if (code != 0) {
424*148c5f43SAlan Wright 		(void) snprintf(msg, sizeof (msg), "smbns_ksetpwd: failed to "
425*148c5f43SAlan Wright 		    "generate key (%d)", enctype);
426*148c5f43SAlan Wright 		smb_krb5_log_errmsg(ctx, msg, code);
427da6c28aaSamw 		free(entry);
428da6c28aaSamw 		return (-1);
429da6c28aaSamw 	}
430da6c28aaSamw 
431da6c28aaSamw 	(void) memcpy(&entry->key, &key, sizeof (krb5_keyblock));
432da6c28aaSamw 	entry->vno = kvno;
433da6c28aaSamw 	entry->principal = princ;
434da6c28aaSamw 
435da6c28aaSamw 	if ((code = krb5_kt_add_entry(ctx, kt, entry)) != 0) {
436*148c5f43SAlan Wright 		(void) snprintf(msg, sizeof (msg), "smbns_ksetpwd: failed to "
437*148c5f43SAlan Wright 		    "add key (%d)", enctype);
438*148c5f43SAlan Wright 		smb_krb5_log_errmsg(ctx, msg, code);
439da6c28aaSamw 		rc = -1;
440da6c28aaSamw 	}
441da6c28aaSamw 
442da6c28aaSamw 	free(entry);
443cbfb650aScp160787 	if (key.length)
444cbfb650aScp160787 		krb5_free_keyblock_contents(ctx, &key);
445da6c28aaSamw 	return (rc);
446da6c28aaSamw }
447*148c5f43SAlan Wright 
448*148c5f43SAlan Wright static int
smb_krb5_spn_count(uint32_t type)449*148c5f43SAlan Wright smb_krb5_spn_count(uint32_t type)
450*148c5f43SAlan Wright {
451*148c5f43SAlan Wright 	int i, cnt;
452*148c5f43SAlan Wright 
453*148c5f43SAlan Wright 	for (i = 0, cnt = 0; i < SMB_KRB5_SPN_TAB_SZ; i++) {
454*148c5f43SAlan Wright 		if (smb_krb5_pn_tab[i].p_flags & type)
455*148c5f43SAlan Wright 			cnt++;
456*148c5f43SAlan Wright 	}
457*148c5f43SAlan Wright 
458*148c5f43SAlan Wright 	return (cnt);
459*148c5f43SAlan Wright }
460*148c5f43SAlan Wright 
461*148c5f43SAlan Wright /*
462*148c5f43SAlan Wright  * Generate the Kerberos Principal given a principal name format and the
463*148c5f43SAlan Wright  * fully qualified domain name. On success, caller must free the allocated
464*148c5f43SAlan Wright  * memory by calling krb5_free_principal().
465*148c5f43SAlan Wright  */
466*148c5f43SAlan Wright static int
smb_krb5_get_kprinc(krb5_context ctx,smb_krb5_pn_id_t id,uint32_t type,const char * fqdn,krb5_principal * princ)467*148c5f43SAlan Wright smb_krb5_get_kprinc(krb5_context ctx, smb_krb5_pn_id_t id, uint32_t type,
468*148c5f43SAlan Wright     const char *fqdn, krb5_principal *princ)
469*148c5f43SAlan Wright {
470*148c5f43SAlan Wright 	char *buf;
471*148c5f43SAlan Wright 
472*148c5f43SAlan Wright 	if ((buf = smb_krb5_get_pn_by_id(id, type, fqdn)) == NULL)
473*148c5f43SAlan Wright 		return (-1);
474*148c5f43SAlan Wright 
475*148c5f43SAlan Wright 	if (krb5_parse_name(ctx, buf, princ) != 0) {
476*148c5f43SAlan Wright 		free(buf);
477*148c5f43SAlan Wright 		return (-1);
478*148c5f43SAlan Wright 	}
479*148c5f43SAlan Wright 
480*148c5f43SAlan Wright 	free(buf);
481*148c5f43SAlan Wright 	return (0);
482*148c5f43SAlan Wright }
483*148c5f43SAlan Wright 
484*148c5f43SAlan Wright /*
485*148c5f43SAlan Wright  * Looks up an entry in the principal name table given the ID.
486*148c5f43SAlan Wright  */
487*148c5f43SAlan Wright static smb_krb5_pn_t *
smb_krb5_lookup_pn(smb_krb5_pn_id_t id)488*148c5f43SAlan Wright smb_krb5_lookup_pn(smb_krb5_pn_id_t id)
489*148c5f43SAlan Wright {
490*148c5f43SAlan Wright 	int i;
491*148c5f43SAlan Wright 	smb_krb5_pn_t *tabent;
492*148c5f43SAlan Wright 
493*148c5f43SAlan Wright 	for (i = 0; i < SMB_KRB5_SPN_TAB_SZ; i++) {
494*148c5f43SAlan Wright 		tabent = &smb_krb5_pn_tab[i];
495*148c5f43SAlan Wright 		if (id == tabent->p_id)
496*148c5f43SAlan Wright 			return (tabent);
497*148c5f43SAlan Wright 	}
498*148c5f43SAlan Wright 
499*148c5f43SAlan Wright 	return (NULL);
500*148c5f43SAlan Wright }
501*148c5f43SAlan Wright 
502*148c5f43SAlan Wright /*
503*148c5f43SAlan Wright  * Construct the principal name given an ID, the requested type, and the
504*148c5f43SAlan Wright  * fully-qualified name of the domain of which the principal is a member.
505*148c5f43SAlan Wright  */
506*148c5f43SAlan Wright static char *
smb_krb5_get_pn_by_id(smb_krb5_pn_id_t id,uint32_t type,const char * fqdn)507*148c5f43SAlan Wright smb_krb5_get_pn_by_id(smb_krb5_pn_id_t id, uint32_t type,
508*148c5f43SAlan Wright     const char *fqdn)
509*148c5f43SAlan Wright {
510*148c5f43SAlan Wright 	char nbname[NETBIOS_NAME_SZ];
511*148c5f43SAlan Wright 	char hostname[MAXHOSTNAMELEN];
512*148c5f43SAlan Wright 	char *realm = NULL;
513*148c5f43SAlan Wright 	smb_krb5_pn_t *pn;
514*148c5f43SAlan Wright 	char *buf;
515*148c5f43SAlan Wright 
516*148c5f43SAlan Wright 	(void) smb_getnetbiosname(nbname, NETBIOS_NAME_SZ);
517*148c5f43SAlan Wright 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, SMB_CASE_LOWER);
518*148c5f43SAlan Wright 
519*148c5f43SAlan Wright 	pn = smb_krb5_lookup_pn(id);
520*148c5f43SAlan Wright 
521*148c5f43SAlan Wright 	/* detect inconsistent requested format and type */
522*148c5f43SAlan Wright 	if ((type & pn->p_flags) != type)
523*148c5f43SAlan Wright 		return (NULL);
524*148c5f43SAlan Wright 
525*148c5f43SAlan Wright 	switch (id) {
526*148c5f43SAlan Wright 	case SMB_KRB5_PN_ID_SALT:
527*148c5f43SAlan Wright 		(void) asprintf(&buf, "%s/%s.%s",
528*148c5f43SAlan Wright 		    pn->p_svc, smb_strlwr(nbname), fqdn);
529*148c5f43SAlan Wright 		break;
530*148c5f43SAlan Wright 
531*148c5f43SAlan Wright 	case SMB_KRB5_PN_ID_HOST_FQHN:
532*148c5f43SAlan Wright 	case SMB_KRB5_PN_ID_NFS_FQHN:
533*148c5f43SAlan Wright 	case SMB_KRB5_PN_ID_HTTP_FQHN:
534*148c5f43SAlan Wright 	case SMB_KRB5_PN_ID_ROOT_FQHN:
535*148c5f43SAlan Wright 		(void) asprintf(&buf, "%s/%s.%s",
536*148c5f43SAlan Wright 		    pn->p_svc, hostname, fqdn);
537*148c5f43SAlan Wright 		break;
538*148c5f43SAlan Wright 	}
539*148c5f43SAlan Wright 
540*148c5f43SAlan Wright 	/*
541*148c5f43SAlan Wright 	 * If the requested principal is either added to keytab / the machine
542*148c5f43SAlan Wright 	 * account as the UPN attribute or used for key salt generation,
543*148c5f43SAlan Wright 	 * the principal name must have the @<REALM> portion.
544*148c5f43SAlan Wright 	 */
545*148c5f43SAlan Wright 	if (type & (SMB_PN_KEYTAB_ENTRY | SMB_PN_UPN_ATTR | SMB_PN_SALT)) {
546*148c5f43SAlan Wright 		if ((realm = strdup(fqdn)) == NULL) {
547*148c5f43SAlan Wright 			free(buf);
548*148c5f43SAlan Wright 			return (NULL);
549*148c5f43SAlan Wright 		}
550*148c5f43SAlan Wright 
551*148c5f43SAlan Wright 		(void) smb_strupr(realm);
552*148c5f43SAlan Wright 		if (buf != NULL) {
553*148c5f43SAlan Wright 			char *tmp;
554*148c5f43SAlan Wright 
555*148c5f43SAlan Wright 			(void) asprintf(&tmp, "%s@%s", buf,
556*148c5f43SAlan Wright 			    realm);
557*148c5f43SAlan Wright 			free(buf);
558*148c5f43SAlan Wright 			buf = tmp;
559*148c5f43SAlan Wright 		}
560*148c5f43SAlan Wright 
561*148c5f43SAlan Wright 		free(realm);
562*148c5f43SAlan Wright 	}
563*148c5f43SAlan Wright 
564*148c5f43SAlan Wright 	return (buf);
565*148c5f43SAlan Wright }
566