summaryrefslogtreecommitdiffstats
path: root/src/kadmin/server/schpw.c
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2009-01-03 23:19:42 +0000
committerSam Hartman <hartmans@mit.edu>2009-01-03 23:19:42 +0000
commit0ba5ccd7bb3ea15e44a87f84ca6feed8890f657d (patch)
tree2049c9c2cb135fe36b14c0a171711259258d18ec /src/kadmin/server/schpw.c
parentff0a6514c9f4230938c29922d69cbd4e83691adf (diff)
downloadkrb5-0ba5ccd7bb3ea15e44a87f84ca6feed8890f657d.tar.gz
krb5-0ba5ccd7bb3ea15e44a87f84ca6feed8890f657d.tar.xz
krb5-0ba5ccd7bb3ea15e44a87f84ca6feed8890f657d.zip
Merge mskrb-integ onto trunk
The mskrb-integ branch includes support for the following projects: Projects/Aliases * Projects/PAC and principal APIs * Projects/AEAD encryption API * Projects/GSSAPI DCE * Projects/RFC 3244 In addition, it includes support for enctype negotiation, and a variety of GSS-API extensions. In the KDC it includes support for protocol transition, constrained delegation and a new authorization data interface. The old authorization data interface is also supported. This commit merges the mskrb-integ branch on to the trunk. Additional review and testing is required. Merge commit 'mskrb-integ' into trunk ticket: new status: open git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21690 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/kadmin/server/schpw.c')
-rw-r--r--src/kadmin/server/schpw.c241
1 files changed, 142 insertions, 99 deletions
diff --git a/src/kadmin/server/schpw.c b/src/kadmin/server/schpw.c
index e8a6896e7..53f2e59ba 100644
--- a/src/kadmin/server/schpw.c
+++ b/src/kadmin/server/schpw.c
@@ -11,37 +11,40 @@
#define GETSOCKNAME_ARG3_TYPE int
#endif
+#define RFC3244_VERSION 0xff80
+
krb5_error_code
-process_chpw_request(context, server_handle, realm, s, keytab, sockin,
- req, rep)
+process_chpw_request(context, server_handle, realm, keytab,
+ local_faddr, remote_faddr, req, rep)
krb5_context context;
void *server_handle;
char *realm;
- int s;
krb5_keytab keytab;
- struct sockaddr_in *sockin;
+ krb5_fulladdr *local_faddr;
+ krb5_fulladdr *remote_faddr;
krb5_data *req;
krb5_data *rep;
{
krb5_error_code ret;
char *ptr;
int plen, vno;
- krb5_address local_kaddr, remote_kaddr;
- int allocated_mem = 0;
krb5_data ap_req, ap_rep;
krb5_auth_context auth_context;
krb5_principal changepw;
+ krb5_principal client, target = NULL;
krb5_ticket *ticket;
krb5_data cipher, clear;
- struct sockaddr local_addr, remote_addr;
- GETSOCKNAME_ARG3_TYPE addrlen;
krb5_replay_data replay;
krb5_error krberror;
int numresult;
char strresult[1024];
- char *clientstr;
+ char *clientstr = NULL, *targetstr = NULL;
size_t clen;
char *cdots;
+ struct sockaddr_storage ss;
+ socklen_t salen;
+ char addrbuf[100];
+ krb5_address *addr = remote_faddr->address;
ret = 0;
rep->length = 0;
@@ -77,7 +80,7 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin,
vno = (*ptr++ & 0xff) ;
vno = (vno<<8) | (*ptr++ & 0xff);
- if (vno != 1) {
+ if (vno != 1 && vno != RFC3244_VERSION) {
ret = KRB5KDC_ERR_BAD_PVNO;
numresult = KRB5_KPASSWD_BAD_VERSION;
snprintf(strresult, sizeof(strresult),
@@ -139,61 +142,6 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin,
goto chpwfail;
}
- /* set up address info */
-
- addrlen = sizeof(local_addr);
-
- if (getsockname(s, &local_addr, &addrlen) < 0) {
- ret = errno;
- numresult = KRB5_KPASSWD_HARDERROR;
- strlcpy(strresult, "Failed getting server internet address",
- sizeof(strresult));
- goto chpwfail;
- }
-
- /* 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);
- allocated_mem++;
-
- krb5_free_addresses(context, addrs);
- }
-
- addrlen = sizeof(remote_addr);
-
- if (getpeername(s, &remote_addr, &addrlen) < 0) {
- ret = errno;
- numresult = KRB5_KPASSWD_HARDERROR;
- strlcpy(strresult, "Failed getting client internet address",
- sizeof(strresult));
- goto chpwfail;
- }
-
- 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);
-
- remote_kaddr.addrtype = ADDRTYPE_INET;
- remote_kaddr.length = sizeof(sockin->sin_addr);
- remote_kaddr.contents = (krb5_octet *) &sockin->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
@@ -209,7 +157,7 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin,
is specified. Are we having fun yet? */
ret = krb5_auth_con_setaddrs(context, auth_context, NULL,
- &remote_kaddr);
+ remote_faddr->address);
if (ret) {
numresult = KRB5_KPASSWD_HARDERROR;
strlcpy(strresult, "Failed storing client internet address",
@@ -217,15 +165,6 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin,
goto chpwfail;
}
- /* verify that this is an AS_REQ ticket */
-
- if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) {
- numresult = KRB5_KPASSWD_AUTHERROR;
- strlcpy(strresult, "Ticket must be derived from a password",
- sizeof(strresult));
- goto chpwfail;
- }
-
/* construct the ap-rep */
ret = krb5_mk_rep(context, auth_context, &ap_rep);
@@ -236,7 +175,7 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin,
goto chpwfail;
}
- /* decrypt the new password */
+ /* decrypt the ChangePasswdData */
cipher.length = (req->data + req->length) - ptr;
cipher.data = ptr;
@@ -248,20 +187,62 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin,
goto chpwfail;
}
- ret = krb5_unparse_name(context, ticket->enc_part2->client, &clientstr);
+ client = ticket->enc_part2->client;
+
+ /* decode ChangePasswdData for setpw requests */
+ if (vno == RFC3244_VERSION) {
+ krb5_data *clear_data;
+
+ ret = decode_krb5_setpw_req(&clear, &clear_data, &target);
+ if (ret != 0) {
+ numresult = KRB5_KPASSWD_MALFORMED;
+ strlcpy(strresult, "Failed decoding ChangePasswdData",
+ sizeof(strresult));
+ goto chpwfail;
+ }
+
+ memset(clear.data, 0, clear.length);
+ free(clear.data);
+
+ clear = *clear_data;
+ free(clear_data);
+
+ if (target != NULL) {
+ ret = krb5_unparse_name(context, target, &targetstr);
+ if (ret != 0) {
+ numresult = KRB5_KPASSWD_HARDERROR;
+ strlcpy(strresult, "Failed unparsing target name for log",
+ sizeof(strresult));
+ goto chpwfail;
+ }
+ }
+ }
+
+ ret = krb5_unparse_name(context, client, &clientstr);
if (ret) {
numresult = KRB5_KPASSWD_HARDERROR;
strlcpy(strresult, "Failed unparsing client name for log",
sizeof(strresult));
goto chpwfail;
}
+
+ /* for cpw, verify that this is an AS_REQ ticket */
+ if (vno == 1 &&
+ (ticket->enc_part2->flags & TKT_FLG_INITIAL) == 0) {
+ numresult = KRB5_KPASSWD_INITIAL_FLAG_NEEDED;
+ strlcpy(strresult, "Ticket must be derived from a password",
+ sizeof(strresult));
+ goto chpwfail;
+ }
+
/* change the password */
ptr = (char *) malloc(clear.length+1);
memcpy(ptr, clear.data, clear.length);
ptr[clear.length] = '\0';
- ret = schpw_util_wrapper(server_handle, ticket->enc_part2->client,
+ ret = schpw_util_wrapper(server_handle, client, target,
+ (ticket->enc_part2->flags & TKT_FLG_INITIAL) != 0,
ptr, NULL, strresult, sizeof(strresult));
/* zap the password */
@@ -273,27 +254,85 @@ process_chpw_request(context, server_handle, realm, s, keytab, sockin,
clen = strlen(clientstr);
trunc_name(&clen, &cdots);
- krb5_klog_syslog(LOG_NOTICE, "chpw request from %s for %.*s%s: %s",
- inet_ntoa(((struct sockaddr_in *)&remote_addr)->sin_addr),
- (int) clen, clientstr, cdots,
- ret ? krb5_get_error_message (context, ret) : "success");
- krb5_free_unparsed_name(context, clientstr);
- if (ret) {
- if ((ret != KADM5_PASS_Q_TOOSHORT) &&
- (ret != KADM5_PASS_REUSE) && (ret != KADM5_PASS_Q_CLASS) &&
- (ret != KADM5_PASS_Q_DICT) && (ret != KADM5_PASS_TOOSOON))
- numresult = KRB5_KPASSWD_HARDERROR;
- else
- numresult = KRB5_KPASSWD_SOFTERROR;
- /* strresult set by kadb5_chpass_principal_util() */
- goto chpwfail;
+ switch (addr->addrtype) {
+ case ADDRTYPE_INET: {
+ struct sockaddr_in *sin = ss2sin(&ss);
+
+ sin->sin_family = AF_INET;
+ memcpy(&sin->sin_addr, addr->contents, addr->length);
+ sin->sin_port = htons(remote_faddr->port);
+ salen = sizeof(*sin);
+ break;
+ }
+ case ADDRTYPE_INET6: {
+ struct sockaddr_in6 *sin6 = ss2sin6(&ss);
+
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr, addr->contents, addr->length);
+ sin6->sin6_port = htons(remote_faddr->port);
+ salen = sizeof(*sin6);
+ break;
}
+ default: {
+ struct sockaddr *sa = ss2sa(&ss);
+
+ sa->sa_family = AF_UNSPEC;
+ salen = sizeof(*sa);
+ break;
+ }
+ }
+
+ if (getnameinfo(ss2sa(&ss), salen,
+ addrbuf, sizeof(addrbuf), NULL, 0,
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0)
+ strlcpy(addrbuf, "<unprintable>", sizeof(addrbuf));
- /* success! */
+ if (vno == RFC3244_VERSION) {
+ size_t tlen;
+ char *tdots;
+ const char *targetp;
- numresult = KRB5_KPASSWD_SUCCESS;
- strlcpy(strresult, "", sizeof(strresult));
+ if (target == NULL) {
+ tlen = clen;
+ tdots = cdots;
+ targetp = targetstr;
+ } else {
+ tlen = strlen(targetstr);
+ trunc_name(&tlen, &tdots);
+ targetp = clientstr;
+ }
+
+ krb5_klog_syslog(LOG_NOTICE, "setpw request from %s by %.*s%s for %.*s%s: %s",
+ addrbuf,
+ (int) clen, clientstr, cdots,
+ (int) tlen, targetp, tdots,
+ ret ? krb5_get_error_message (context, ret) : "success");
+ } else {
+ krb5_klog_syslog(LOG_NOTICE, "chpw request from %s for %.*s%s: %s",
+ addrbuf,
+ (int) clen, clientstr, cdots,
+ ret ? krb5_get_error_message (context, ret) : "success");
+ }
+ switch (ret) {
+ case KADM5_AUTH_CHANGEPW:
+ numresult = KRB5_KPASSWD_ACCESSDENIED;
+ break;
+ case KADM5_PASS_Q_TOOSHORT:
+ case KADM5_PASS_REUSE:
+ case KADM5_PASS_Q_CLASS:
+ case KADM5_PASS_Q_DICT:
+ case KADM5_PASS_TOOSOON:
+ numresult = KRB5_KPASSWD_HARDERROR;
+ break;
+ case 0:
+ numresult = KRB5_KPASSWD_SUCCESS;
+ strlcpy(strresult, "", sizeof(strresult));
+ break;
+ default:
+ numresult = KRB5_KPASSWD_SOFTERROR;
+ break;
+ }
chpwfail:
@@ -310,8 +349,8 @@ chpwfail:
cipher.length = 0;
if (ap_rep.length) {
- ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr,
- NULL);
+ ret = krb5_auth_con_setaddrs(context, auth_context,
+ local_faddr->address, NULL);
if (ret) {
numresult = KRB5_KPASSWD_HARDERROR;
strlcpy(strresult,
@@ -422,8 +461,12 @@ bailout:
krb5_xfree(clear.data);
if (cipher.length)
krb5_xfree(cipher.data);
- if (allocated_mem)
- krb5_xfree(local_kaddr.contents);
+ if (target)
+ krb5_free_principal(context, target);
+ if (targetstr)
+ krb5_free_unparsed_name(context, targetstr);
+ if (clientstr)
+ krb5_free_unparsed_name(context, clientstr);
return(ret);
}