+
+int get_krb5_error(krb5_error_code rc, char *in, char *out)
+{
+ int krb5Error;
+ int retval;
+
+ retval = 1;
+
+ if (rc < 0)
+ {
+ krb5Error = ((int)(rc & 255));
+ sprintf(out, "%s: %s(%ld)", in, error_message(rc), krb5Error);
+ }
+ else
+ {
+ switch (rc)
+ {
+ case KDC_RECEIVE_TIMEOUT:
+ {
+ retval = 0;
+ sprintf(out, "%s: %s(%d)", in, "Receive timeout", rc);
+ break;
+ }
+ case KDC_RECEIVE_ERROR:
+ {
+ retval = 0;
+ sprintf(out, "%s: %s(%d)", in, "Receive error", rc);
+ break;
+ }
+ case KRB5_KPASSWD_MALFORMED:
+ {
+ sprintf(out, "%s: %s(%d)", in, "malformed password", rc);
+ break;
+ }
+ case KRB5_KPASSWD_HARDERROR:
+ {
+ sprintf(out, "%s: %s(%d)", in, "hard error", rc);
+ break;
+ }
+ case KRB5_KPASSWD_AUTHERROR:
+ {
+ retval = 0;
+ sprintf(out, "%s: %s(%d)", in, "authentication error", rc);
+ break;
+ }
+ case KRB5_KPASSWD_SOFTERROR:
+ {
+ retval = 0;
+ sprintf(out, "%s: %s(%d)", in, "soft error", rc);
+ break;
+ }
+ case KRB5_KPASSWD_ACCESSDENIED:
+ {
+ sprintf(out, "%s: %s(%d)", in, "Access denied", rc);
+ break;
+ }
+ case KDC_SEND_ERROR:
+ {
+ retval = 0;
+ sprintf(out, "%s: %s(%d)", in, "Send error", rc);
+ break;
+ }
+ case KDC_GETSOCKNAME_ERROR:
+ {
+ retval = 0;
+ sprintf(out, "%s: %s(%d)", in, "Socket error - getsockname", rc);
+ break;
+ }
+ case KDC_GETPEERNAME_ERROR:
+ {
+ retval = 0;
+ sprintf(out, "%s: %s(%d)", in, "Socket error - getpeername", rc);
+ break;
+ }
+ default:
+ {
+ sprintf(out, "%s: %s(%d)", in, "unknown error", rc);
+ break;
+ }
+ }
+ }
+ return(retval);
+}
+
+int ad_connect(LDAP **ldap_handle, char *ldap_domain, char *dn_path,
+ char *Win2kPassword, char *Win2kUser, char *default_server,
+ int connect_to_kdc)
+{
+ int i;
+ int j;
+ char *server_name[MAX_SERVER_NAMES];
+ char server_array[MAX_SERVER_NAMES][256];
+ static char temp[128];
+ ULONG version = LDAP_VERSION3;
+ ULONG rc;
+ int Max_wait_time = 500;
+ int Max_size_limit = LDAP_NO_LIMIT;
+
+ if (ldap_domain == NULL)
+ ldap_domain = "win.mit.edu";
+ convert_domain_to_dn(ldap_domain, dn_path);
+ if (strlen(dn_path) == 0)
+ return(1);
+
+ memset(server_name, 0, sizeof(server_name[0]) * MAX_SERVER_NAMES);
+ memset(server_array, 0, sizeof(server_array[0]) * MAX_SERVER_NAMES);
+ if (strlen(default_server) == 0)
+ {
+ if (locate_ldap_server(ldap_domain, server_name) == -1)
+ return(2);
+ j = 0;
+ for (i = 0; i < MAX_SERVER_NAMES; i++)
+ {
+ if (server_name[i] != NULL)
+ {
+ strcpy(server_array[i], server_name[i]);
+ free(server_name[i]);
+ j++;
+ }
+ }
+ if (j == 0)
+ return(2);
+#ifdef _WIN32
+ qsort((void *)server_array, (size_t)j, sizeof(server_array[0]), compare_elements);
+#endif
+ }
+ else
+ strcpy(server_array[0], default_server);
+
+ for (i = 0; i < MAX_SERVER_NAMES; i++)
+ {
+ if (strlen(server_array[i]) != 0)
+ {
+ if (((*ldap_handle) = ldap_open(server_array[i], LDAP_PORT)) != NULL)
+ {
+ rc = ldap_set_option((*ldap_handle), LDAP_OPT_PROTOCOL_VERSION, &version);
+ rc = ldap_set_option((*ldap_handle), LDAP_OPT_TIMELIMIT,
+ (void *)&Max_wait_time);
+ rc = ldap_set_option((*ldap_handle), LDAP_OPT_SIZELIMIT,
+ (void *)&Max_size_limit);
+ rc = ldap_set_option((*ldap_handle), LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+ rc = ldap_adgssapi_bind((*ldap_handle), dn_path, GSSSASL_PRIVACY_PROTECTION);
+ if (rc == LDAP_SUCCESS)
+ {
+ if (connect_to_kdc)
+ {
+ if (!ad_server_connect(server_array[i], ldap_domain))
+ {
+ ldap_unbind_s((*ldap_handle));
+ continue;
+ }
+ }
+ if (strlen(default_server) == 0)
+ strcpy(default_server, server_array[i]);
+ strcpy(connected_server, server_array[i]);
+ break;
+ }
+ }
+ }
+ }
+ if (i >= MAX_SERVER_NAMES)
+ return(3);
+ return(0);
+}
+
+int ad_server_connect(char *connectedServer, char *domain)
+{
+ krb5_error_code rc;
+ krb5_creds creds;
+ krb5_creds *credsp;
+ char temp[256];
+ char userrealm[256];
+ int i;
+ unsigned short port = KDC_PORT;
+
+ context = NULL;
+ credsp = NULL;
+ memset(&ccache, 0, sizeof(ccache));
+ memset(&creds, 0, sizeof(creds));
+ memset(userrealm, '\0', sizeof(userrealm));
+
+ rc = 0;
+ if (krb5_init_context(&context))
+ goto cleanup;
+ if (krb5_cc_default(context, &ccache))
+ goto cleanup;
+
+ for (i = 0; i < (int)strlen(domain); i++)
+ userrealm[i] = toupper(domain[i]);
+ sprintf(temp, "%s@%s", "kadmin/changepw", userrealm);
+ if (krb5_parse_name(context, temp, &creds.server))
+ goto cleanup;
+ if (krb5_cc_get_principal(context, ccache, &creds.client))
+ goto cleanup;
+ if (krb5_get_credentials(context, 0, ccache, &creds, &credsp))
+ goto cleanup;
+
+ rc = ad_kdc_connect(connectedServer);
+
+
+cleanup:
+ if (!rc)
+ {
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+ }
+ krb5_free_cred_contents(context, &creds);
+ if (credsp != NULL)
+ krb5_free_creds(context, credsp);
+ return(rc);
+}
+
+
+int ad_kdc_connect(char *connectedServer)
+{
+ struct hostent *hp;
+ int rc;
+
+ rc = 0;
+ hp = gethostbyname(connectedServer);
+ if (hp == NULL)
+ goto cleanup;
+ memset(&kdc_server, 0, sizeof(kdc_server));
+ memcpy(&(kdc_server.sin_addr),hp->h_addr_list[0],hp->h_length);
+ kdc_server.sin_family = hp->h_addrtype;
+ kdc_server.sin_port = htons(KDC_PORT);
+
+ if ((kdc_socket = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
+ goto cleanup;
+ if (connect(kdc_socket, (struct sockaddr*)&kdc_server, sizeof(kdc_server)) == SOCKET_ERROR)
+ goto cleanup;
+ rc = 1;
+
+cleanup:
+ return(rc);
+}
+
+void ad_kdc_disconnect()
+{
+
+ if (auth_context != NULL)
+ {
+ krb5_auth_con_free(context, auth_context);
+ if (ap_req.data != NULL)
+ free(ap_req.data);
+ krb5_free_cred_contents(context, &creds);
+ if (credsp != NULL)
+ krb5_free_creds(context, credsp);
+ }
+ credsp = NULL;
+ auth_context = NULL;
+ if (context != NULL)
+ {
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+ }
+ closesocket(kdc_socket);
+
+}
+
+int convert_domain_to_dn(char *domain, char *dnp)
+{
+ char *fp;
+ char *dp;
+ char dn[512];
+
+ memset(dn, '\0', sizeof(dn));
+ strcpy(dn, "dc=");
+ dp = dn+3;
+ for (fp = domain; *fp; fp++)
+ {
+ if (*fp == '.')
+ {
+ strcpy(dp, ",dc=");
+ dp += 4;
+ }
+ else
+ *dp++ = *fp;
+ }
+
+ strcpy(dnp, dn);
+ return 0;
+}
+
+int compare_elements(const void *arg1, const void *arg2)
+{
+ int rc;
+
+ rc = strcmp((char*)arg1, (char*)arg2);
+ if (rc < 0)
+ return(1);
+ if (rc > 0)
+ return(-1);
+ return(rc);
+}
+