diff options
| author | Sam Hartman <hartmans@mit.edu> | 2009-01-03 23:19:42 +0000 |
|---|---|---|
| committer | Sam Hartman <hartmans@mit.edu> | 2009-01-03 23:19:42 +0000 |
| commit | 0ba5ccd7bb3ea15e44a87f84ca6feed8890f657d (patch) | |
| tree | 2049c9c2cb135fe36b14c0a171711259258d18ec /src/kadmin/server/schpw.c | |
| parent | ff0a6514c9f4230938c29922d69cbd4e83691adf (diff) | |
| download | krb5-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.c | 241 |
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); } |
