Changeset 740 for vendor/current/source4/kdc/pac-glue.c
- Timestamp:
- Nov 14, 2012, 12:59:34 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source4/kdc/pac-glue.c
r414 r740 1 /* 1 /* 2 2 Unix SMB/CIFS implementation. 3 3 4 4 PAC Glue between Samba and the KDC 5 5 6 6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009 7 Copyright (C) Simo Sorce <idra@samba.org> 2010 7 8 8 9 This program is free software; you can redistribute it and/or modify … … 10 11 the Free Software Foundation; either version 3 of the License, or 11 12 (at your option) any later version. 12 13 13 14 This program is distributed in the hope that it will be useful, 14 15 but WITHOUT ANY WARRANTY; without even the implied warranty of … … 16 17 GNU General Public License for more details. 17 18 18 19 19 20 You should have received a copy of the GNU General Public License 20 21 along with this program. If not, see <http://www.gnu.org/licenses/>. … … 23 24 #include "includes.h" 24 25 #include "../libds/common/flags.h" 25 #include "lib/ldb/include/ldb.h" 26 #include <ldb.h> 27 #include "auth/auth.h" 28 #include "auth/auth_sam_reply.h" 29 #include "kdc/kdc-glue.h" 30 #include "param/param.h" 26 31 #include "librpc/gen_ndr/ndr_krb5pac.h" 27 #include "librpc/gen_ndr/krb5pac.h" 28 #include "auth/auth.h" 29 #include "auth/auth_sam.h" 30 #include "auth/auth_sam_reply.h" 31 #include "kdc/kdc.h" 32 #include "param/param.h" 33 34 struct krb5_dh_moduli; 35 struct _krb5_krb_auth_data; 36 37 static krb5_error_code samba_kdc_plugin_init(krb5_context context, void **ptr) 38 { 39 *ptr = NULL; 40 return 0; 41 } 42 43 static void samba_kdc_plugin_fini(void *ptr) 44 { 45 return; 46 } 47 48 static krb5_error_code make_pac(krb5_context context, 49 TALLOC_CTX *mem_ctx, 50 struct smb_iconv_convenience *iconv_convenience, 51 struct auth_serversupplied_info *server_info, 52 krb5_pac *pac) 53 { 54 union PAC_INFO info; 32 33 static 34 NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx, 35 struct auth_user_info_dc *info, 36 DATA_BLOB *pac_data) 37 { 55 38 struct netr_SamInfo3 *info3; 56 krb5_data pac_data; 57 NTSTATUS nt_status; 39 union PAC_INFO pac_info; 58 40 enum ndr_err_code ndr_err; 59 DATA_BLOB pac_out; 60 krb5_error_code ret; 61 62 ZERO_STRUCT(info); 63 64 nt_status = auth_convert_server_info_saminfo3(mem_ctx, server_info, &info3); 41 NTSTATUS nt_status; 42 43 ZERO_STRUCT(pac_info); 44 45 nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info, &info3); 65 46 if (!NT_STATUS_IS_OK(nt_status)) { 66 DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status))); 67 return EINVAL; 68 } 69 70 info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO); 47 DEBUG(1, ("Getting Samba info failed: %s\n", 48 nt_errstr(nt_status))); 49 return nt_status; 50 } 51 52 pac_info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO); 71 53 if (!mem_ctx) { 72 return ENOMEM;73 } 74 75 info.logon_info.info->info3 = *info3;76 77 ndr_err = ndr_push_union_blob( &pac_out, mem_ctx, iconv_convenience, &info,54 return NT_STATUS_NO_MEMORY; 55 } 56 57 pac_info.logon_info.info->info3 = *info3; 58 59 ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info, 78 60 PAC_TYPE_LOGON_INFO, 79 61 (ndr_push_flags_fn_t)ndr_push_PAC_INFO); 80 62 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 81 63 nt_status = ndr_map_error2ntstatus(ndr_err); 82 DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status))); 83 return EINVAL; 84 } 85 86 ret = krb5_data_copy(&pac_data, pac_out.data, pac_out.length); 64 DEBUG(1, ("PAC (presig) push failed: %s\n", 65 nt_errstr(nt_status))); 66 return nt_status; 67 } 68 69 return NT_STATUS_OK; 70 } 71 72 krb5_error_code samba_make_krb5_pac(krb5_context context, 73 DATA_BLOB *pac_blob, 74 krb5_pac *pac) 75 { 76 krb5_data pac_data; 77 krb5_error_code ret; 78 79 /* The user account may be set not to want the PAC */ 80 if (!pac_blob) { 81 return 0; 82 } 83 84 ret = krb5_data_copy(&pac_data, pac_blob->data, pac_blob->length); 87 85 if (ret != 0) { 88 86 return ret; … … 104 102 } 105 103 106 /* Given the right private pointer from hdb_samba4, get a PAC from the attached ldb messages */ 107 static krb5_error_code samba_kdc_get_pac(void *priv, 108 krb5_context context, 109 struct hdb_entry_ex *client, 110 krb5_pac *pac) 111 { 112 krb5_error_code ret; 113 NTSTATUS nt_status; 114 struct auth_serversupplied_info *server_info; 115 struct hdb_samba4_private *p = talloc_get_type(client->ctx, struct hdb_samba4_private); 116 TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_get_pac context"); 117 unsigned int userAccountControl; 118 119 if (!mem_ctx) { 120 return ENOMEM; 121 } 122 123 /* The user account may be set not to want the PAC */ 104 bool samba_princ_needs_pac(struct hdb_entry_ex *princ) 105 { 106 107 struct samba_kdc_entry *p = talloc_get_type(princ->ctx, struct samba_kdc_entry); 108 uint32_t userAccountControl; 109 110 111 /* The service account may be set not to want the PAC */ 124 112 userAccountControl = ldb_msg_find_attr_as_uint(p->msg, "userAccountControl", 0); 125 113 if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) { 126 *pac = NULL; 127 return 0; 128 } 129 130 nt_status = authsam_make_server_info(mem_ctx, p->samdb, 131 lp_netbios_name(p->lp_ctx), 132 lp_sam_name(p->lp_ctx), 114 return false; 115 } 116 117 return true; 118 } 119 120 /* Was the krbtgt an RODC (and we are not) */ 121 bool samba_krbtgt_was_untrusted_rodc(struct hdb_entry_ex *princ) 122 { 123 124 struct samba_kdc_entry *p = talloc_get_type(princ->ctx, struct samba_kdc_entry); 125 int rodc_krbtgt_number; 126 127 /* Determine if this was printed by an RODC */ 128 rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1); 129 if (rodc_krbtgt_number == -1) { 130 return false; 131 } else if (rodc_krbtgt_number != p->kdc_db_ctx->my_krbtgt_number) { 132 return true; 133 } 134 135 return false; 136 } 137 138 NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx, 139 struct hdb_entry_ex *client, 140 DATA_BLOB **_pac_blob) 141 { 142 struct samba_kdc_entry *p = talloc_get_type(client->ctx, struct samba_kdc_entry); 143 struct auth_user_info_dc *user_info_dc; 144 DATA_BLOB *pac_blob; 145 NTSTATUS nt_status; 146 147 /* The user account may be set not to want the PAC */ 148 if ( ! samba_princ_needs_pac(client)) { 149 *_pac_blob = NULL; 150 return NT_STATUS_OK; 151 } 152 153 pac_blob = talloc_zero(mem_ctx, DATA_BLOB); 154 if (!pac_blob) { 155 return NT_STATUS_NO_MEMORY; 156 } 157 158 nt_status = authsam_make_user_info_dc(mem_ctx, p->kdc_db_ctx->samdb, 159 lpcfg_netbios_name(p->kdc_db_ctx->lp_ctx), 160 lpcfg_sam_name(p->kdc_db_ctx->lp_ctx), 133 161 p->realm_dn, 134 162 p->msg, 135 163 data_blob(NULL, 0), 136 164 data_blob(NULL, 0), 137 & server_info);165 &user_info_dc); 138 166 if (!NT_STATUS_IS_OK(nt_status)) { 139 167 DEBUG(0, ("Getting user info for PAC failed: %s\n", 140 168 nt_errstr(nt_status))); 141 return ENOMEM; 142 } 143 144 ret = make_pac(context, mem_ctx, p->iconv_convenience, server_info, pac); 145 146 talloc_free(mem_ctx); 147 return ret; 148 } 149 150 /* Resign (and reform, including possibly new groups) a PAC */ 151 152 static krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context, 153 const krb5_principal client_principal, 154 struct hdb_entry_ex *client, 155 struct hdb_entry_ex *server, krb5_pac *pac) 156 { 169 return nt_status; 170 } 171 172 nt_status = samba_get_logon_info_pac_blob(mem_ctx, user_info_dc, pac_blob); 173 if (!NT_STATUS_IS_OK(nt_status)) { 174 DEBUG(0, ("Building PAC failed: %s\n", 175 nt_errstr(nt_status))); 176 return nt_status; 177 } 178 179 *_pac_blob = pac_blob; 180 return NT_STATUS_OK; 181 } 182 183 NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, 184 krb5_context context, 185 krb5_pac *pac, DATA_BLOB *pac_blob) 186 { 187 struct auth_user_info_dc *user_info_dc; 157 188 krb5_error_code ret; 158 159 unsigned int userAccountControl; 160 161 struct hdb_samba4_private *p = talloc_get_type(server->ctx, struct hdb_samba4_private); 162 163 struct auth_serversupplied_info *server_info_out; 164 165 TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_get_pac context"); 166 167 if (!mem_ctx) { 168 return ENOMEM; 169 } 170 171 /* The service account may be set not to want the PAC */ 172 userAccountControl = ldb_msg_find_attr_as_uint(p->msg, "userAccountControl", 0); 173 if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) { 174 talloc_free(mem_ctx); 175 *pac = NULL; 176 return 0; 177 } 178 179 ret = kerberos_pac_to_server_info(mem_ctx, p->iconv_convenience, 180 *pac, context, &server_info_out); 181 182 /* We will compleatly regenerate this pac */ 183 krb5_pac_free(context, *pac); 184 189 NTSTATUS nt_status; 190 191 ret = kerberos_pac_to_user_info_dc(mem_ctx, *pac, 192 context, &user_info_dc, NULL, NULL); 185 193 if (ret) { 186 talloc_free(mem_ctx);187 return ret;188 } 189 190 ret = make_pac(context, mem_ctx, p->iconv_convenience, server_info_out, pac);191 192 talloc_free(mem_ctx);193 return ret; 194 } 195 196 static void samba_kdc_build_edata_reply(TALLOC_CTX *tmp_ctx, krb5_data *e_data, 197 NTSTATUS nt_status)194 return NT_STATUS_UNSUCCESSFUL; 195 } 196 197 nt_status = samba_get_logon_info_pac_blob(mem_ctx, 198 user_info_dc, pac_blob); 199 200 return nt_status; 201 } 202 203 /* this function allocates 'data' using malloc. 204 * The caller is responsible for freeing it */ 205 void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data) 198 206 { 199 207 PA_DATA pa; … … 227 235 } 228 236 229 /* Given an hdb entry (and in particular it's private member), consult 230 * the account_ok routine in auth/auth_sam.c for consistancy */ 231 232 233 static krb5_error_code samba_kdc_check_client_access(void *priv, 234 krb5_context context, 235 krb5_kdc_configuration *config, 236 hdb_entry_ex *client_ex, const char *client_name, 237 hdb_entry_ex *server_ex, const char *server_name, 238 KDC_REQ *req, 239 krb5_data *e_data) 237 /* function to map policy errors */ 238 krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status) 240 239 { 241 240 krb5_error_code ret; 242 NTSTATUS nt_status; 241 242 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) 243 ret = KRB5KDC_ERR_KEY_EXPIRED; 244 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) 245 ret = KRB5KDC_ERR_KEY_EXPIRED; 246 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) 247 ret = KRB5KDC_ERR_CLIENT_REVOKED; 248 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) 249 ret = KRB5KDC_ERR_CLIENT_REVOKED; 250 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) 251 ret = KRB5KDC_ERR_CLIENT_REVOKED; 252 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) 253 ret = KRB5KDC_ERR_CLIENT_REVOKED; 254 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) 255 ret = KRB5KDC_ERR_POLICY; 256 else 257 ret = KRB5KDC_ERR_POLICY; 258 259 return ret; 260 } 261 262 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c 263 * for consistency */ 264 NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry, 265 const char *client_name, 266 const char *workstation, 267 bool password_change) 268 { 243 269 TALLOC_CTX *tmp_ctx; 244 struct hdb_samba4_private *p; 245 char *workstation = NULL; 246 HostAddresses *addresses = req->req_body.addresses; 247 int i; 248 bool password_change; 249 250 tmp_ctx = talloc_new(client_ex->ctx); 251 p = talloc_get_type(client_ex->ctx, struct hdb_samba4_private); 252 270 NTSTATUS nt_status; 271 272 tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access"); 253 273 if (!tmp_ctx) { 254 return ENOMEM; 255 } 256 257 if (addresses) { 258 for (i=0; i < addresses->len; i++) { 259 if (addresses->val->addr_type == KRB5_ADDRESS_NETBIOS) { 260 workstation = talloc_strndup(tmp_ctx, addresses->val->address.data, MIN(addresses->val->address.length, 15)); 261 if (workstation) { 262 break; 263 } 264 } 265 } 266 } 267 268 /* Strip space padding */ 269 if (workstation) { 270 i = MIN(strlen(workstation), 15); 271 for (; i > 0 && workstation[i - 1] == ' '; i--) { 272 workstation[i - 1] = '\0'; 273 } 274 } 275 276 password_change = (server_ex && server_ex->entry.flags.change_pw); 274 return NT_STATUS_NO_MEMORY; 275 } 277 276 278 277 /* we allow all kinds of trusts here */ 279 nt_status = authsam_account_ok(tmp_ctx, 280 p->samdb, 281 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, 282 p->realm_dn, 283 p->msg, 284 workstation, 285 client_name, true, password_change); 286 287 if (NT_STATUS_IS_OK(nt_status)) { 288 /* Now do the standard Heimdal check */ 289 ret = kdc_check_flags(context, config, 290 client_ex, client_name, 291 server_ex, server_name, 292 req->msg_type == krb_as_req); 293 } else { 294 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) 295 ret = KRB5KDC_ERR_KEY_EXPIRED; 296 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) 297 ret = KRB5KDC_ERR_KEY_EXPIRED; 298 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) 299 ret = KRB5KDC_ERR_CLIENT_REVOKED; 300 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) 301 ret = KRB5KDC_ERR_CLIENT_REVOKED; 302 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) 303 ret = KRB5KDC_ERR_CLIENT_REVOKED; 304 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) 305 ret = KRB5KDC_ERR_CLIENT_REVOKED; 306 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) 307 ret = KRB5KDC_ERR_POLICY; 308 else 309 ret = KRB5KDC_ERR_POLICY; 310 311 samba_kdc_build_edata_reply(tmp_ctx, e_data, nt_status); 312 } 313 314 return ret; 315 } 316 317 struct krb5plugin_windc_ftable windc_plugin_table = { 318 .minor_version = KRB5_WINDC_PLUGING_MINOR, 319 .init = samba_kdc_plugin_init, 320 .fini = samba_kdc_plugin_fini, 321 .pac_generate = samba_kdc_get_pac, 322 .pac_verify = samba_kdc_reget_pac, 323 .client_access = samba_kdc_check_client_access, 324 }; 325 278 nt_status = authsam_account_ok(tmp_ctx, 279 kdc_entry->kdc_db_ctx->samdb, 280 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | 281 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, 282 kdc_entry->realm_dn, kdc_entry->msg, 283 workstation, client_name, 284 true, password_change); 285 286 talloc_free(tmp_ctx); 287 return nt_status; 288 } 289
Note:
See TracChangeset
for help on using the changeset viewer.