#include <sys/timeb.h>
#include <errno.h>
-
#define PW_LENGTH 25
#ifndef krb5_is_krb_error
#define krb5_is_krb_error(dat)\
- ((dat) && (dat)->length && ((dat)->data[0] == 0x7e ||\
- (dat)->data[0] == 0x5e))
+ ((dat) && (dat)->length && ((dat)->data[0] == 0x7e ||\
+ (dat)->data[0] == 0x5e))
#endif
/* Win32 defines. */
*/
static int row_sums[26] =
-{796, 160, 284, 401, 1276, 262, 199, 539, 777,
- 16, 39, 351, 243, 751, 662, 181, 17, 683,
- 662, 968, 248, 115, 180, 17, 162, 5};
+{796,160,284,401,1276,262,199,539,777,
+ 16,39,351,243,751,662,181,17,683,
+ 662,968,248,115,180,17,162,5};
/*
* Frequencies of starting characters
*/
static int start_freq [26] =
-{1299, 425, 725, 271, 375, 470, 93, 223, 1009,
- 24, 20, 355, 379, 319, 823, 618, 21, 317,
- 962, 1991, 271, 104, 516, 6, 16, 14};
+{1299,425,725,271,375,470,93,223,1009,
+ 24,20,355,379,319,823,618,21,317,
+ 962,1991,271,104,516,6,16,14};
/*
* This MUST be equal to the sum of all elements in the above array.
void generate_password(char *password);
int set_password(char *user, char *domain);
krb5_error_code encode_krb5_setpw
- PROTOTYPE((const krb5_setpw *rep, krb5_data ** code));
+ PROTOTYPE((const krb5_setpw *rep, krb5_data ** code));
krb5_error_code
krb5_locate_kpasswd(krb5_context context, const krb5_data *realm,
struct sockaddr **addr_pp, int *naddrs);
memset (&setpw, 0, sizeof(krb5_setpw));
if (ret = krb5_auth_con_setflags(context, auth_context,
KRB5_AUTH_CONTEXT_DO_SEQUENCE))
- return(ret);
+ return(ret);
setpw.targprinc = targprinc;
setpw.newpasswd.length = strlen(passwd);
setpw.newpasswd.data = passwd;
if ((ret = encode_krb5_setpw(&setpw, &encoded_setpw)))
- return( ret );
+ return( ret );
if (ret = krb5_mk_priv(context, auth_context,
- encoded_setpw, &cipherpw, &replay))
- return(ret);
+ encoded_setpw, &cipherpw, &replay))
+ return(ret);
packet->length = 6 + ap_req->length + cipherpw.length;
packet->data = (char *) malloc(packet->length);
ptr = packet->data;
krb5_ap_rep_enc_part *ap_rep_enc;
if (packet->length < 4)
- return(KRB5KRB_AP_ERR_MODIFIED);
+ return(KRB5KRB_AP_ERR_MODIFIED);
ptr = packet->data;
if (krb5_is_krb_error(packet))
{
- ret = decode_krb5_error(packet, &krberror);
- if (ret)
- return(ret);
- ret = krberror->error;
- krb5_free_error(context, krberror);
- return(ret);
+ ret = decode_krb5_error(packet, &krberror);
+ if (ret)
+ return(ret);
+ ret = krberror->error;
+ krb5_free_error(context, krberror);
+ return(ret);
}
/* verify length */
plen = (*ptr++ & 0xff);
plen = (plen<<8) | (*ptr++ & 0xff);
if (plen != packet->length)
- return(KRB5KRB_AP_ERR_MODIFIED);
+ return(KRB5KRB_AP_ERR_MODIFIED);
vno = (*ptr++ & 0xff);
vno = (vno<<8) | (*ptr++ & 0xff);
if (vno != KRB5_KPASSWD_VERS_SETPW && vno != KRB5_KPASSWD_VERS_CHANGEPW)
- return(KRB5KDC_ERR_BAD_PVNO);
+ return(KRB5KDC_ERR_BAD_PVNO);
/* read, check ap-rep length */
ap_rep.length = (*ptr++ & 0xff);
ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff);
if (ptr + ap_rep.length >= packet->data + packet->length)
- return(KRB5KRB_AP_ERR_MODIFIED);
+ return(KRB5KRB_AP_ERR_MODIFIED);
if (ap_rep.length)
{
- /* verify ap_rep */
- ap_rep.data = ptr;
- ptr += ap_rep.length;
- if (ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc))
- return(ret);
- krb5_free_ap_rep_enc_part(context, ap_rep_enc);
- /* extract and decrypt the result */
- cipherresult.data = ptr;
- cipherresult.length = (packet->data + packet->length) - ptr;
- /* XXX there's no api to do this right. The problem is that
- if there's a remote subkey, it will be used. This is
- not what the spec requires */
- tmp = auth_context->remote_subkey;
- auth_context->remote_subkey = NULL;
- ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
- &replay);
- auth_context->remote_subkey = tmp;
- if (ret)
- return(ret);
+ /* verify ap_rep */
+ ap_rep.data = ptr;
+ ptr += ap_rep.length;
+ if (ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc))
+ return(ret);
+ krb5_free_ap_rep_enc_part(context, ap_rep_enc);
+ /* extract and decrypt the result */
+ cipherresult.data = ptr;
+ cipherresult.length = (packet->data + packet->length) - ptr;
+ /* XXX there's no api to do this right. The problem is that
+ if there's a remote subkey, it will be used. This is
+ not what the spec requires */
+ tmp = auth_context->remote_subkey;
+ auth_context->remote_subkey = NULL;
+ ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
+ &replay);
+ auth_context->remote_subkey = tmp;
+ if (ret)
+ return(ret);
}
else
{
- cipherresult.data = ptr;
- cipherresult.length = (packet->data + packet->length) - ptr;
-
- if (ret = krb5_rd_error(context, &cipherresult, &krberror))
- return(ret);
-
- clearresult = krberror->e_data;
+ cipherresult.data = ptr;
+ cipherresult.length = (packet->data + packet->length) - ptr;
+ if (ret = krb5_rd_error(context, &cipherresult, &krberror))
+ return(ret);
+ clearresult = krberror->e_data;
}
if (clearresult.length < 2)
{
- ret = KRB5KRB_AP_ERR_MODIFIED;
- goto cleanup;
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto cleanup;
}
ptr = clearresult.data;
*result_code = (*ptr++ & 0xff);
*result_code = (*result_code<<8) | (*ptr++ & 0xff);
if ((*result_code < KRB5_KPASSWD_SUCCESS) ||
- (*result_code > KRB5_KPASSWD_ACCESSDENIED))
+ (*result_code > KRB5_KPASSWD_ACCESSDENIED))
{
- ret = KRB5KRB_AP_ERR_MODIFIED;
- goto cleanup;
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto cleanup;
}
/* all success replies should be authenticated/encrypted */
if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS))
{
- ret = KRB5KRB_AP_ERR_MODIFIED;
- goto cleanup;
+ ret = KRB5KRB_AP_ERR_MODIFIED;
+ goto cleanup;
}
result_data->length = (clearresult.data + clearresult.length) - ptr;
if (result_data->length)
{
- result_data->data = (char *) malloc(result_data->length);
- memcpy(result_data->data, ptr, result_data->length);
+ result_data->data = (char *) malloc(result_data->length);
+ memcpy(result_data->data, ptr, result_data->length);
}
else
- result_data->data = NULL;
+ result_data->data = NULL;
ret = 0;
cleanup:
if (ap_rep.length)
- free(clearresult.data);
+ free(clearresult.data);
else
- krb5_free_error(context, krberror);
+ krb5_free_error(context, krberror);
return(ret);
}
int tmp_len;
int error_count;
krb5_principal targprinc;
- struct timeval TimeVal;
- fd_set readfds;
+ int count;
+ int last_count;
auth_context = NULL;
addr_p = NULL;
memset(userrealm, '\0', sizeof(userrealm));
targprinc = NULL;
for (i = 0; i < (int)strlen(domain); i++)
- userrealm[i] = toupper(domain[i]);
+ userrealm[i] = toupper(domain[i]);
sprintf(temp, "%s@%s", user, userrealm);
krb5_parse_name(context, temp, &targprinc);
if (code = krb5_get_credentials(context, 0, ccache, &creds, &credsp))
goto cleanup;
if (code = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
- NULL, credsp, &ap_req))
+ NULL, credsp, &ap_req))
+ goto cleanup;
+ if (code = krb5_locate_kpasswd(context, &targprinc->realm, &addr_p, &out))
goto cleanup;
- if (code = krb5_locate_kpasswd(context, &targprinc->realm, &addr_p, &out))
- goto cleanup;
if (out == 0)
{ /* Couldn't resolve any KPASSWD names */
code = 1;
goto cleanup;
}
- /* this is really obscure. s1 is used for all communications. it
- is left unconnected in case the server is multihomed and routes
- are asymmetric. s2 is connected to resolve routes and get
- addresses. this is the *only* way to get proper addresses for
- multihomed hosts if routing is asymmetric.
-
- A related problem in the server, but not the client, is that
- many os's have no way to disconnect a connected udp socket, so
- the s2 socket needs to be closed and recreated for each
- request. The s1 socket must not be closed, or else queued
- requests will be lost.
-
- A "naive" client implementation (one socket, no connect,
- hostname resolution to get the local ip addr) will work and
- interoperate if the client is single-homed. */
-
if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
free(addr_p);
- return(errno);
+ return(errno);
}
if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
closesocket(s1);
free(addr_p);
- return(errno);
+ return(errno);
}
error_count = 0;
for (i=0; i<out; i++)
{
- if (connect(s2, &addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR)
+ if (connect(s2, &addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR)
continue;
-
- addrlen = sizeof(local_addr);
- if (getsockname(s2, &local_addr, &addrlen) < 0)
+ addrlen = sizeof(local_addr);
+ if (getsockname(s2, &local_addr, &addrlen) < 0)
continue;
- if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0)
+ if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0)
{
- local_kaddr.addrtype = ADDRTYPE_INET;
- local_kaddr.length =
- sizeof(((struct sockaddr_in *) &local_addr)->sin_addr);
- local_kaddr.contents =
- (char *) &(((struct sockaddr_in *) &local_addr)->sin_addr);
- }
+printf("1\n");
+ local_kaddr.addrtype = ADDRTYPE_INET;
+ local_kaddr.length =
+ sizeof(((struct sockaddr_in *) &local_addr)->sin_addr);
+ local_kaddr.contents =
+ (char *) &(((struct sockaddr_in *) &local_addr)->sin_addr);
+ }
else
{
- krb5_address **addrs;
- krb5_os_localaddr(context, &addrs);
- local_kaddr.magic = addrs[0]->magic;
- local_kaddr.addrtype = addrs[0]->addrtype;
- local_kaddr.length = addrs[0]->length;
- local_kaddr.contents = calloc(1, addrs[0]->length);
- memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
- krb5_free_addresses(context, addrs);
- }
-
- addrlen = sizeof(remote_addr);
- if (getpeername(s2, &remote_addr, &addrlen) < 0)
- continue;
- remote_kaddr.addrtype = ADDRTYPE_INET;
- remote_kaddr.length =
- sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr);
- remote_kaddr.contents =
- (char *) &(((struct sockaddr_in *) &remote_addr)->sin_addr);
- /* mk_priv requires that the local address be set.
- getsockname is used for this. rd_priv requires that the
- remote address be set. recvfrom is used for this. If
- rd_priv is given a local address, and the message has the
- recipient addr in it, this will be checked. However, there
- is simply no way to know ahead of time what address the
- message will be delivered *to*. Therefore, it is important
- that either no recipient address is in the messages when
- mk_priv is called, or that no local address is passed to
- rd_priv. Both is a better idea, and I have done that. In
- summary, when mk_priv is called, *only* a local address is
- specified. when rd_priv is called, *only* a remote address
- is specified. Are we having fun yet? */
- if (code = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL))
+ krb5_address **addrs;
+ krb5_os_localaddr(context, &addrs);
+ local_kaddr.magic = addrs[0]->magic;
+ local_kaddr.addrtype = addrs[0]->addrtype;
+ local_kaddr.length = addrs[0]->length;
+ local_kaddr.contents = calloc(1, addrs[0]->length);
+ memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
+ krb5_free_addresses(context, addrs);
+ }
+
+ addrlen = sizeof(remote_addr);
+ if (getpeername(s2, &remote_addr, &addrlen) < 0)
+ continue;
+ remote_kaddr.addrtype = ADDRTYPE_INET;
+ remote_kaddr.length =
+ sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr);
+ remote_kaddr.contents =
+ (char *) &(((struct sockaddr_in *) &remote_addr)->sin_addr);
+
+ if (code = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL))
goto cleanup;
- if (code = krb5_mk_setpw_req(context, auth_context, &ap_req,
- targprinc, newpw, &chpw_req))
+ if (code = krb5_mk_setpw_req(context, auth_context, &ap_req,
+ targprinc, newpw, &chpw_req))
goto cleanup;
- if ((cc = sendto(s1, chpw_req.data, chpw_req.length, 0,
- (struct sockaddr *) &addr_p[i],
- sizeof(addr_p[i]))) != chpw_req.length)
- continue; /* try the next addr */
-#ifdef _WIN32
- krb5_free_data_contents(context, &chpw_req);
-#else
- free(chpw_req.data);
-#endif
- chpw_rep.length = 1500;
- chpw_rep.data = (char *) calloc(1, chpw_rep.length);
- /* XXX need a timeout/retry loop here */
- /* "recv" would be good enough here... except that Windows/NT
- commits the atrocity of returning -1 to indicate failure,
- but leaving errno set to 0.
-
- "recvfrom(...,NULL,NULL)" would seem to be a good enough
- alternative, and it works on NT, but it doesn't work on
- SunOS 4.1.4 or Irix 5.3. Thus we must actually accept the
- value and discard it. */
- tmp_len = sizeof(tmp_addr);
- TimeVal.tv_sec = 10;
- TimeVal.tv_usec = 0;
-
- FD_ZERO(&readfds);
- FD_SET(s1, &readfds);
- code = select(1, &readfds, NULL, NULL, &TimeVal);
-
- if ((code == 0) || (code == SOCKET_ERROR))
+
+ if ((cc = sendto(s1, chpw_req.data, chpw_req.length, 0,
+ (struct sockaddr *) &addr_p[i],
+ sizeof(addr_p[i]))) != chpw_req.length)
+ continue;
+
+ if (chpw_req.data != NULL)
+ free(chpw_req.data);
+ chpw_rep.length = 1500;
+ chpw_rep.data = (char *) calloc(1, chpw_rep.length);
+
+ tmp_len = sizeof(tmp_addr);
+ last_count = 0;
+ while (1)
{
- if (error_count < 2)
+ cc = recvfrom(s1, chpw_rep.data, chpw_rep.length, MSG_PEEK,
+ &tmp_addr, &tmp_len);
+ if ((last_count == cc) && (cc != 0))
+ break;
+ last_count = cc;
+ if (cc == 0)
{
- closesocket(s1);
- closesocket(s2);
- if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
- goto cleanup;
- if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
- goto cleanup;
- ++error_count;
- --i;
- continue;
+ if (last_count == -1)
+ break;
+ last_count = -1;
}
- code = errno;
- goto cleanup;
+ sleep(1);
}
- if ((cc = recvfrom(s1, chpw_rep.data, chpw_rep.length, 0, &tmp_addr, &tmp_len)) < 0)
+ if ((cc = recvfrom(s1, chpw_rep.data, chpw_rep.length, 0, &tmp_addr, &tmp_len)) < 0)
{
code = errno;
goto cleanup;
- }
- chpw_rep.length = cc;
- if (code = krb5_auth_con_setaddrs(context, auth_context, NULL,
- &remote_kaddr))
+ }
+ chpw_rep.length = cc;
+ if (code = krb5_auth_con_setaddrs(context, auth_context, NULL,
+ &remote_kaddr))
{
goto cleanup;
- }
+ }
local_result_code = 0;
- code = krb5_rd_setpw_rep(context, auth_context, &chpw_rep,
- &local_result_code, &result_string);
+ code = krb5_rd_setpw_rep(context, auth_context, &chpw_rep,
+ &local_result_code, &result_string);
- if (result_code)
- *result_code = local_result_code;
-#ifdef _WIN32
- krb5_free_data_contents(context, &chpw_req);
-#else
- free(chpw_req.data);
-#endif
+ if (local_result_code)
+ {
+ if (local_result_code == KRB5_KPASSWD_SOFTERROR)
+ local_result_code = KRB5_KPASSWD_SUCCESS;
+ *result_code = local_result_code;
+ }
+ if (chpw_rep.data != NULL)
+ free(chpw_rep.data);
break;
}
if (auth_context != NULL)
krb5_auth_con_free(context, auth_context);
if (ap_req.data != NULL)
-#ifdef _WIN32
- krb5_free_data_contents(context, &ap_req);
-#else
- free(ap_req.data);
-#endif
+ free(ap_req.data);
krb5_free_cred_contents(context, &creds);
if (credsp != NULL)
krb5_free_creds(context, credsp);
if (targprinc != NULL)
krb5_free_principal(context, targprinc);
- return(code);
+ return(code);
}
int set_password(char *user, char *domain)
krb5_ccache ccache;
int res_code;
krb5_error_code retval;
- char pw[PW_LENGTH+1];
+ char pw[PW_LENGTH+1];
if (retval = krb5_init_context(&context))
return retval;
if (retval = krb5_cc_default(context, &ccache))
- return(retval);
+ return(retval);
memset(pw, '\0', sizeof(pw));
generate_password(pw);
+ res_code = 0;
retval = krb5_set_password(context, ccache, pw, user, domain, &res_code);
- krb5_cc_close(context, ccache);
- krb5_free_context(context);
- return(retval);
+ krb5_cc_close(context, ccache);
+ krb5_free_context(context);
+ if (retval)
+ return(retval);
+ return(res_code);
}
void generate_password(char *password)
{
- int i;
+ int i;
int j;
int row_position;
int nchars;
int position;
- int word;
+ int word;
int line;
- char *pwp;
+ char *pwp;
- for (line = 22; line; --line)
+ for (line = 22; line; --line)
{
for (word = 7; word; --word)
{
}
*(++pwp)='\0';
return;
- }
+ }
putchar('\n');
}
}