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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <unistd.h> 34 #include <ctype.h> 35 #include <errno.h> 36 #include <syslog.h> 37 #include <fcntl.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <kerberosv5/krb5.h> 41 42 static int smb_krb5_ktadd(krb5_context ctx, krb5_keytab kt, 43 const krb5_principal princ, krb5_enctype enctype, krb5_kvno kvno, 44 const char *pw); 45 46 /* 47 * smb_krb5_ctx_init 48 * 49 * Initialize the kerberos context. 50 * Return 0 on success. Otherwise, return -1. 51 */ 52 int 53 smb_krb5_ctx_init(krb5_context *ctx) 54 { 55 if (krb5_init_context(ctx) != 0) 56 return (-1); 57 58 return (0); 59 } 60 61 /* 62 * smb_krb5_get_principal 63 * 64 * Setup the krb5_principal given the host principal in string format. 65 * Return 0 on success. Otherwise, return -1. 66 */ 67 int 68 smb_krb5_get_principal(krb5_context ctx, char *princ_str, krb5_principal *princ) 69 { 70 if (krb5_parse_name(ctx, princ_str, princ) != 0) 71 return (-1); 72 73 return (0); 74 } 75 76 /* 77 * smb_krb5_ctx_fini 78 * 79 * Free the kerberos context. 80 */ 81 void 82 smb_krb5_ctx_fini(krb5_context ctx) 83 { 84 krb5_free_context(ctx); 85 } 86 87 /* 88 * smb_ksetpw 89 * 90 * Set the workstation trust account password. 91 * Returns 0 on success. Otherwise, returns non-zero value. 92 */ 93 int 94 smb_krb5_setpwd(krb5_context ctx, krb5_principal princ, char *passwd) 95 { 96 krb5_error_code code; 97 krb5_ccache cc = NULL; 98 int result_code; 99 krb5_data result_code_string, result_string; 100 101 (void) memset(&result_code_string, 0, sizeof (result_code_string)); 102 (void) memset(&result_string, 0, sizeof (result_string)); 103 104 if ((code = krb5_cc_default(ctx, &cc)) != 0) { 105 syslog(LOG_ERR, "smb_krb5_setpwd: failed to find a ccache\n"); 106 return (-1); 107 } 108 109 code = krb5_set_password_using_ccache(ctx, cc, passwd, princ, 110 &result_code, &result_code_string, &result_string); 111 112 krb5_cc_close(ctx, cc); 113 114 if (code != 0) 115 (void) syslog(LOG_ERR, 116 "smb_krb5_setpwd: Result: %.*s (%d) %.*s\n", 117 result_code == 0 ? 118 strlen("success") : result_code_string.length, 119 result_code == 0 ? "success" : result_code_string.data, 120 result_code, result_string.length, result_string.data); 121 return (code); 122 } 123 124 /* 125 * smb_krb5_write_keytab 126 * 127 * Write all the Kerberos keys to the keytab file. 128 * Returns 0 on success. Otherwise, returns -1. 129 */ 130 int 131 smb_krb5_write_keytab(krb5_context ctx, krb5_principal princ, char *fname, 132 krb5_kvno kvno, char *passwd, krb5_enctype *enctypes, int enctype_count) 133 { 134 krb5_keytab kt = NULL; 135 char *ktname; 136 int i, len; 137 int rc = 0; 138 struct stat fstat; 139 140 if (stat(fname, &fstat) == 0) { 141 if (remove(fname) != 0) { 142 syslog(LOG_ERR, "smb_krb5_write_keytab: cannot remove" 143 " existing keytab"); 144 return (-1); 145 } 146 } 147 148 len = snprintf(NULL, 0, "WRFILE:%s", fname) + 1; 149 if ((ktname = malloc(len)) == NULL) { 150 syslog(LOG_ERR, "smb_krb5_write_keytab: resource shortage"); 151 return (-1); 152 } 153 154 (void) snprintf(ktname, len, "WRFILE:%s", fname); 155 156 if (krb5_kt_resolve(ctx, ktname, &kt) != 0) { 157 syslog(LOG_ERR, "smb_krb5_write_keytab: failed to open/create " 158 "keytab %s\n", fname); 159 free(ktname); 160 return (-1); 161 } 162 163 free(ktname); 164 165 for (i = 0; i < enctype_count; i++) { 166 if (smb_krb5_ktadd(ctx, kt, princ, enctypes[i], kvno, passwd) 167 != 0) { 168 rc = -1; 169 break; 170 } 171 172 } 173 174 if (kt != NULL) 175 krb5_kt_close(ctx, kt); 176 177 return (rc); 178 } 179 180 /* 181 * smb_krb5_ktadd 182 * 183 * Add a Keberos key to the keytab file. 184 * Returns 0 on success. Otherwise, returns -1. 185 */ 186 static int 187 smb_krb5_ktadd(krb5_context ctx, krb5_keytab kt, const krb5_principal princ, 188 krb5_enctype enctype, krb5_kvno kvno, const char *pw) 189 { 190 krb5_keytab_entry *entry; 191 krb5_data password, salt; 192 krb5_keyblock key; 193 krb5_error_code code; 194 char buf[100]; 195 int rc = 0; 196 197 if ((code = krb5_enctype_to_string(enctype, buf, sizeof (buf)))) { 198 syslog(LOG_ERR, "smb_krb5_ktadd[%d]: unknown enctype", 199 enctype); 200 return (-1); 201 } 202 203 if ((entry = (krb5_keytab_entry *) malloc(sizeof (*entry))) == NULL) { 204 syslog(LOG_ERR, "smb_krb5_ktadd[%d]: resource shortage", 205 enctype); 206 return (-1); 207 } 208 209 (void) memset((char *)entry, 0, sizeof (*entry)); 210 211 password.length = strlen(pw); 212 password.data = (char *)pw; 213 214 if ((code = krb5_principal2salt(ctx, princ, &salt)) != 0) { 215 syslog(LOG_ERR, "smb_krb5_ktadd[%d]: failed to compute salt", 216 enctype); 217 free(entry); 218 return (-1); 219 } 220 221 code = krb5_c_string_to_key(ctx, enctype, &password, &salt, &key); 222 krb5_xfree(salt.data); 223 if (code != 0) { 224 syslog(LOG_ERR, "smb_krb5_ktadd[%d]: failed to generate key", 225 enctype); 226 free(entry); 227 return (-1); 228 } 229 230 (void) memcpy(&entry->key, &key, sizeof (krb5_keyblock)); 231 entry->vno = kvno; 232 entry->principal = princ; 233 234 if ((code = krb5_kt_add_entry(ctx, kt, entry)) != 0) { 235 syslog(LOG_ERR, "smb_krb5_ktadd[%d] failed to add entry to " 236 "keytab (%d)", enctype, code); 237 rc = -1; 238 } 239 240 free(entry); 241 return (rc); 242 } 243