ad-joining/ksetpwd/ksetpwd.c (176 lines of code) (raw):

// // Copyright 2019 Google LLC // // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // #include <stdio.h> #include <locale.h> #include <sys/types.h> #include <krb5.h> #define NAME "ksetpwd" static int authenticate_agent( /* [IN] */ krb5_context context, /* [IN] */ krb5_principal agent_principal, /* [IN, OPT] */ char *agent_principal_password, /* [OUT] */ krb5_creds *agent_creds) { int result; krb5_get_init_creds_opt *opts; result = krb5_get_init_creds_opt_alloc(context, &opts); if (result) { com_err(NAME, result, "Initializing options failed"); return 1; } krb5_get_init_creds_opt_set_tkt_life(opts, 5 * 60); krb5_get_init_creds_opt_set_renew_life(opts, 0); krb5_get_init_creds_opt_set_forwardable(opts, 0); krb5_get_init_creds_opt_set_proxiable(opts, 0); result = krb5_get_init_creds_password( context, agent_creds, agent_principal, agent_principal_password, krb5_prompter_posix, NULL, 0, "kadmin/changepw", opts); krb5_get_init_creds_opt_free(context, opts); return result; } static int reset_password( /* [IN] */ krb5_context context, /* [IN] */ krb5_principal agent_principal, /* [IN, OPT] */ char *agent_principal_password, /* [IN] */ krb5_principal target_principal, /* [IN] */ char* new_password) { krb5_error_code ret; krb5_creds agent_creds; int result; char* message = NULL; int server_result = 0; krb5_data server_result_string = {0}; krb5_data server_result_code_string = {0}; const int RESULT_SUCCESS = 0; const int RESULT_FAIL_AUTH_AGENT = 1; const int RESULT_FAIL_SET_PWD_KERBEROS_ERROR = 2; const int RESULT_FAIL_SET_PWD_SERVER_ERROR = 3; // Get initial credentials for agent. result = authenticate_agent(context, agent_principal, agent_principal_password, &agent_creds); if (result != 0) { if (result == KRB5KRB_AP_ERR_BAD_INTEGRITY) { com_err(NAME, 0, "Invalid password for agent principal"); } else if (result == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN) { com_err(NAME, 0, "Agent principal does not exist in Active Directory"); } else { com_err(NAME, ret, "Authenticating agent principal failed with code %d", result); } result = RESULT_FAIL_AUTH_AGENT; goto cleanup; } // Reset password of target principal. result = krb5_set_password( context, &agent_creds, new_password, target_principal, &server_result, &server_result_code_string, &server_result_string); if (result != 0) { result = RESULT_FAIL_SET_PWD_KERBEROS_ERROR; com_err(NAME, ret, "Resetting password failed"); goto cleanup; } if (server_result) { if (krb5_chpw_message(context, &server_result_string, &message) != 0) { message = NULL; } fprintf(stderr, "%.*s%s%s (error code %d)\n", (int)server_result_code_string.length, server_result_code_string.data, message ? ": " : "", message ? message : NULL, server_result); result = RESULT_FAIL_SET_PWD_SERVER_ERROR; goto cleanup; } result = RESULT_SUCCESS; printf("Password changed.\n"); cleanup: if (message != NULL) { krb5_free_string(context, message); } if (server_result_string.data != NULL) { free(server_result_string.data); } if (server_result_code_string.data != NULL) { free(server_result_code_string.data); } return result; } int main( /* [IN] */ int argc, /* [IN] */ char *argv[]) { int result; krb5_context context = NULL; krb5_principal agent_principal = NULL; krb5_principal target_principal = NULL; // Parse command line setlocale(LC_ALL, ""); if (argc < 3) { fprintf(stderr, "usage: %s [agent principal] [principal]\n", NAME); result = 1; goto cleanup; } // Initialize Kerberos. result = krb5_init_context(&context); if (result != 0) { com_err(NAME, result, "Initializing Kerberos failed"); result = 1; goto cleanup; } // Parse principal names. result = krb5_parse_name(context, argv[1], &agent_principal); if (result != 0) { com_err(NAME, result, "Parsing agent principal name failed"); result = 1; goto cleanup; } result = krb5_parse_name(context, argv[2], &target_principal); if (result != 0) { com_err(NAME, result, "Parsing target principal name failed"); result = 1; goto cleanup; } fprintf(stderr, "Resetting password for %s\n", argv[2]); result = reset_password( context, agent_principal, getenv("KSETPWD_AGENT_PASSWORD"), target_principal, getenv("KSETPWD_TARGET_PASSWORD")); cleanup: if (target_principal != NULL) { krb5_free_principal(context, target_principal); } if (agent_principal != NULL) { krb5_free_principal(context, agent_principal); } if (context != NULL) { krb5_free_context(context); } exit(result); }