summaryrefslogtreecommitdiffstats
path: root/src/lib/krb5/os/changepw.c
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@mit.edu>2001-04-26 03:54:43 +0000
committerKen Raeburn <raeburn@mit.edu>2001-04-26 03:54:43 +0000
commit3bbea9e561adf69da5de52caf9e8257b548258af (patch)
tree5f8625a045d431d66b9a887e5adf1110f46f4393 /src/lib/krb5/os/changepw.c
parent64e212fec9aa98416add9f8231ad4359f9931de8 (diff)
downloadkrb5-3bbea9e561adf69da5de52caf9e8257b548258af.tar.gz
krb5-3bbea9e561adf69da5de52caf9e8257b548258af.tar.xz
krb5-3bbea9e561adf69da5de52caf9e8257b548258af.zip
localaddr.c (foreach_localaddr): support SIOCGIFNUM, for Solaris
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13197 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/krb5/os/changepw.c')
-rw-r--r--src/lib/krb5/os/changepw.c476
1 files changed, 231 insertions, 245 deletions
diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c
index 61cfea01f..1eefe6d98 100644
--- a/src/lib/krb5/os/changepw.c
+++ b/src/lib/krb5/os/changepw.c
@@ -8,7 +8,7 @@
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
- *
+ *
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
@@ -22,7 +22,7 @@
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
- *
+ *
*/
#define NEED_SOCKETS
@@ -49,6 +49,21 @@
#endif
#endif /* _WIN32 && !__CYGWIN32__ */
+/* There's a lot of confusion between pointers to different sockaddr
+ types, and pointers with different degrees of indirection. Use
+ this function in this file to ensure we don't do something silly
+ like cast a "sockaddr **" to a "sockaddr_in *". */
+static struct sockaddr_in *sa2sin (struct sockaddr *sa)
+{
+ return (struct sockaddr_in *) sa;
+}
+#ifdef KRB5_USE_INET6xxNotUsed
+static struct sockaddr_in6 *sa2sin6 (struct sockaddr *sa)
+{
+ return (struct sockaddr_in6 *) sa;
+}
+#endif
+
/*
* Wrapper function for the two backends
*/
@@ -57,54 +72,30 @@ static krb5_error_code
krb5_locate_kpasswd(context, realm, addr_pp, naddrs)
krb5_context context;
const krb5_data *realm;
- struct sockaddr **addr_pp;
+ struct sockaddr ***addr_pp;
int *naddrs;
{
krb5_error_code code;
- int i;
- /*
- * We always try the local file first
- */
-
- code = krb5_locate_srv_conf(context, realm, "kpasswd_server",
- addr_pp, naddrs, 0);
+ code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0,
+ "kpasswd_server", "_kpasswd", 0,
+ DEFAULT_KPASSWD_PORT, 0);
if (code) {
- code = krb5_locate_srv_conf(context, realm, "admin_server",
- addr_pp, naddrs, 0);
- if ( !code ) {
- /* success with admin_server but now we need to change the port */
- /* number to use DEFAULT_KPASSWD_PORT. */
- for ( i=0;i<*naddrs;i++ ) {
- struct sockaddr_in *sockin = (struct sockaddr_in *) addr_pp[i];
- sockin->sin_port = htons(DEFAULT_KPASSWD_PORT);
- }
- }
+ code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0,
+ "admin_server", "_kerberos-adm", 1,
+ DEFAULT_KPASSWD_PORT, 0);
+ if (!code) {
+ /* Success with admin_server but now we need to change the
+ port number to use DEFAULT_KPASSWD_PORT. */
+ int i;
+ for ( i=0;i<*naddrs;i++ ) {
+ struct sockaddr *a = (*addr_pp)[i];
+ if (a->sa_family == AF_INET)
+ sa2sin (a)->sin_port = htons(DEFAULT_KPASSWD_PORT);
+ }
+ }
}
-#ifdef KRB5_DNS_LOOKUP
- if (code) {
- int use_dns = _krb5_use_dns_kdc(context);
- if ( use_dns ) {
- code = krb5_locate_srv_dns(realm, "_kpasswd", "_udp",
- addr_pp, naddrs);
- if ( code ) {
- code = krb5_locate_srv_dns(realm,
- "_kerberos-adm",
- "_tcp",
- addr_pp, naddrs);
- if ( !code ) {
- /* success with admin_server but now we need to change the port */
- /* number to use DEFAULT_KPASSWD_PORT. */
- for ( i=0;i<*naddrs;i++ ) {
- struct sockaddr_in *sockin = (struct sockaddr_in *) addr_pp[i];
- sockin->sin_port = htons(DEFAULT_KPASSWD_PORT);
- }
- }
- }
- }
- }
-#endif /* KRB5_DNS_LOOKUP */
return (code);
}
@@ -125,7 +116,7 @@ krb5_change_password(context, creds, newpw, result_code,
char *code_string;
krb5_error_code code = 0;
int i, addrlen;
- struct sockaddr *addr_p, local_addr, remote_addr, tmp_addr;
+ struct sockaddr **addr_p, local_addr, remote_addr, tmp_addr;
int naddr_p;
int cc, local_result_code, tmp_len;
SOCKET s1 = INVALID_SOCKET, s2 = INVALID_SOCKET;
@@ -137,18 +128,18 @@ krb5_change_password(context, creds, newpw, result_code,
memset(&chpw_req, 0, sizeof(krb5_data));
memset(&chpw_rep, 0, sizeof(krb5_data));
memset(&ap_req, 0, sizeof(krb5_data));
-
+
/* initialize auth_context so that we know we have to free it */
if ((code = krb5_auth_con_init(context, &auth_context)))
goto cleanup;
-
- if ((code = krb5_mk_req_extended(context, &auth_context,
+
+ if ((code = krb5_mk_req_extended(context, &auth_context,
AP_OPTS_USE_SUBKEY,
NULL, creds, &ap_req)))
goto cleanup;
- if ((code = krb5_locate_kpasswd(context,
- krb5_princ_realm(context, creds->client),
+ if ((code = krb5_locate_kpasswd(context,
+ krb5_princ_realm(context, creds->client),
&addr_p, &naddr_p)))
goto cleanup;
@@ -156,7 +147,7 @@ krb5_change_password(context, creds, newpw, result_code,
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.
+ 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
@@ -168,212 +159,207 @@ krb5_change_password(context, creds, newpw, result_code,
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)
- {
+ if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ for (i=0; i<naddr_p; i++) {
+ fd_set fdset;
+ struct timeval timeout;
+
+ /* XXX Now the locate_ functions can return IPv6 addresses. */
+ if (addr_p[i]->sa_family != AF_INET)
+ continue;
+
+ if (connect(s2, addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR) {
+ if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+ continue; /* try the next addr */
+
code = SOCKET_ERRNO;
goto cleanup;
- }
+ }
+
+ addrlen = sizeof(local_addr);
+
+ if (getsockname(s2, &local_addr, &addrlen) < 0) {
+ if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+ continue; /* try the next addr */
- if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
- {
code = SOCKET_ERRNO;
goto cleanup;
- }
-
- for (i=0; i<naddr_p; i++)
- {
- fd_set fdset;
- struct timeval timeout;
-
- if (connect(s2, &addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR)
- {
- if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
- continue; /* try the next addr */
-
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- addrlen = sizeof(local_addr);
+ }
- if (getsockname(s2, &local_addr, &addrlen) < 0)
- {
- if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
- continue; /* try the next addr */
-
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- /* some brain-dead OS's don't return useful information from
- * the getsockname call. Namely, windows and solaris. */
-
- 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 = (krb5_octet *) &(((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 = malloc(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)
- {
- if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
- continue; /* try the next addr */
-
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- remote_kaddr.addrtype = ADDRTYPE_INET;
- remote_kaddr.length = sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr);
- remote_kaddr.contents = (krb5_octet *) &(((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)))
- {
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req,
- newpw, &chpw_req)))
- {
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- if ((cc = sendto(s1, chpw_req.data, (int) chpw_req.length, 0,
- (struct sockaddr *) &addr_p[i],
- sizeof(addr_p[i]))) != chpw_req.length)
- {
- if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) ||
- (SOCKET_ERRNO == EHOSTUNREACH)))
- continue; /* try the next addr */
-
- code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED;
- goto cleanup;
- }
-
- chpw_rep.length = 1500;
- chpw_rep.data = (char *) malloc(chpw_rep.length);
-
- /* XXX need a timeout/retry loop here */
- FD_ZERO (&fdset);
- FD_SET (s1, &fdset);
- timeout.tv_sec = 120;
- timeout.tv_usec = 0;
- switch (select (s1 + 1, &fdset, 0, 0, &timeout)) {
- case -1:
- code = SOCKET_ERRNO;
- goto cleanup;
- case 0:
- code = ETIMEDOUT;
- goto cleanup;
- default:
- /* fall through */
- ;
- }
-
- /* "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);
- if ((cc = recvfrom(s1, chpw_rep.data, (int) chpw_rep.length,
- 0, &tmp_addr, &tmp_len)) < 0)
- {
- code = SOCKET_ERRNO;
- goto cleanup;
- }
-
- closesocket(s1);
- s1 = INVALID_SOCKET;
- closesocket(s2);
- s2 = INVALID_SOCKET;
-
- chpw_rep.length = cc;
-
- if ((code = krb5_auth_con_setaddrs(context, auth_context,
- NULL, &remote_kaddr)))
- goto cleanup;
-
- if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep,
- &local_result_code,
- result_string)))
- goto cleanup;
-
- if (result_code)
- *result_code = local_result_code;
-
- if (result_code_string)
- {
- if ((code = krb5_chpw_result_code_string(context,
- local_result_code,
- &code_string)))
- goto cleanup;
-
- result_code_string->length = strlen(code_string);
- if ((result_code_string->data =
- (char *) malloc(result_code_string->length)) == NULL)
- return(ENOMEM);
- strncpy(result_code_string->data, code_string, result_code_string->length);
- }
-
- code = 0;
+ /* some brain-dead OS's don't return useful information from
+ * the getsockname call. Namely, windows and solaris. */
+
+ if (sa2sin(&local_addr)->sin_addr.s_addr != 0) {
+ local_kaddr.addrtype = ADDRTYPE_INET;
+ local_kaddr.length = sizeof(sa2sin(&local_addr)->sin_addr);
+ local_kaddr.contents = (krb5_octet *) &sa2sin(&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 = malloc(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) {
+ if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+ continue; /* try the next addr */
+
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ remote_kaddr.addrtype = ADDRTYPE_INET;
+ remote_kaddr.length = sizeof(sa2sin(&remote_addr)->sin_addr);
+ remote_kaddr.contents = (krb5_octet *) &sa2sin(&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))) {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req,
+ newpw, &chpw_req)))
+ {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ if ((cc = sendto(s1, chpw_req.data, (int) chpw_req.length, 0,
+ addr_p[i], sizeof(addr_p[i]))) != chpw_req.length)
+ {
+ if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) ||
+ (SOCKET_ERRNO == EHOSTUNREACH)))
+ continue; /* try the next addr */
+
+ code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED;
+ goto cleanup;
+ }
+
+ chpw_rep.length = 1500;
+ chpw_rep.data = (char *) malloc(chpw_rep.length);
+
+ /* XXX need a timeout/retry loop here */
+ FD_ZERO (&fdset);
+ FD_SET (s1, &fdset);
+ timeout.tv_sec = 120;
+ timeout.tv_usec = 0;
+ switch (select (s1 + 1, &fdset, 0, 0, &timeout)) {
+ case -1:
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ case 0:
+ code = ETIMEDOUT;
+ goto cleanup;
+ default:
+ /* fall through */
+ ;
+ }
+
+ /* "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);
+ if ((cc = recvfrom(s1, chpw_rep.data, (int) chpw_rep.length,
+ 0, &tmp_addr, &tmp_len)) < 0)
+ {
+ code = SOCKET_ERRNO;
+ goto cleanup;
+ }
+
+ closesocket(s1);
+ s1 = INVALID_SOCKET;
+ closesocket(s2);
+ s2 = INVALID_SOCKET;
+
+ chpw_rep.length = cc;
+
+ if ((code = krb5_auth_con_setaddrs(context, auth_context,
+ NULL, &remote_kaddr)))
+ goto cleanup;
+
+ if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep,
+ &local_result_code,
+ result_string)))
+ goto cleanup;
+
+ if (result_code)
+ *result_code = local_result_code;
+
+ if (result_code_string) {
+ if ((code = krb5_chpw_result_code_string(context,
+ local_result_code,
+ &code_string)))
goto cleanup;
- }
+
+ result_code_string->length = strlen(code_string);
+ if ((result_code_string->data =
+ (char *) malloc(result_code_string->length)) == NULL)
+ return(ENOMEM);
+ strncpy(result_code_string->data, code_string, result_code_string->length);
+ }
+
+ code = 0;
+ goto cleanup;
+ }
code = SOCKET_ERRNO;
-
+
cleanup:
- if(auth_context != NULL)
- krb5_auth_con_free(context, auth_context);
-
- if(addr_p != NULL)
- krb5_xfree(addr_p);
-
- if(s1 != INVALID_SOCKET)
- closesocket(s1);
-
- if(s2 != INVALID_SOCKET)
- closesocket(s2);
-
+ if (auth_context != NULL)
+ krb5_auth_con_free(context, auth_context);
+
+ if (addr_p != NULL) {
+ for (i = 0; i < naddr_p; i++)
+ krb5_xfree (addr_p[i]);
+ krb5_xfree(addr_p);
+ }
+
+ if (s1 != INVALID_SOCKET)
+ closesocket(s1);
+
+ if (s2 != INVALID_SOCKET)
+ closesocket(s2);
+
krb5_free_data_contents(context, &chpw_req);
krb5_free_data_contents(context, &chpw_rep);
- krb5_free_data_contents(context, &ap_req);
-
+ krb5_free_data_contents(context, &ap_req);
+
return(code);
}