s4/drs: add DRSUAPI_ATTRIBUTE_options attribute
[abartlet/samba.git/.git] / source3 / libads / krb5_setpw.c
index 07e6320c266e5d0c555850d1550f6dc3559c165c..ec5cafc49d408a573c0a08cd07669b35799b3dc6 100644 (file)
@@ -6,7 +6,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "smb_krb5.h"
 
 #ifdef HAVE_KRB5
 
@@ -66,7 +66,7 @@ static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
        char* c;
        char* princ;
 
-       ASN1_DATA req;
+       ASN1_DATA *req;
        DATA_BLOB ret;
 
 
@@ -88,43 +88,46 @@ static DATA_BLOB encode_krb5_setpw(const char *principal, const char *password)
                realm = c;
        } else {
                /* We must have a realm component. */
-               return data_blob(NULL, 0);
+               return data_blob_null;
        }
 
-       memset(&req, 0, sizeof(req));
-       
-       asn1_push_tag(&req, ASN1_SEQUENCE(0));
-       asn1_push_tag(&req, ASN1_CONTEXT(0));
-       asn1_write_OctetString(&req, password, strlen(password));
-       asn1_pop_tag(&req);
+       req = asn1_init(talloc_tos());
+       if (req == NULL) {
+               return data_blob_null;
+       }
+
+       asn1_push_tag(req, ASN1_SEQUENCE(0));
+       asn1_push_tag(req, ASN1_CONTEXT(0));
+       asn1_write_OctetString(req, password, strlen(password));
+       asn1_pop_tag(req);
 
-       asn1_push_tag(&req, ASN1_CONTEXT(1));
-       asn1_push_tag(&req, ASN1_SEQUENCE(0));
+       asn1_push_tag(req, ASN1_CONTEXT(1));
+       asn1_push_tag(req, ASN1_SEQUENCE(0));
 
-       asn1_push_tag(&req, ASN1_CONTEXT(0));
-       asn1_write_Integer(&req, 1);
-       asn1_pop_tag(&req);
+       asn1_push_tag(req, ASN1_CONTEXT(0));
+       asn1_write_Integer(req, 1);
+       asn1_pop_tag(req);
 
-       asn1_push_tag(&req, ASN1_CONTEXT(1));
-       asn1_push_tag(&req, ASN1_SEQUENCE(0));
+       asn1_push_tag(req, ASN1_CONTEXT(1));
+       asn1_push_tag(req, ASN1_SEQUENCE(0));
 
        if (princ_part1) {
-               asn1_write_GeneralString(&req, princ_part1);
+               asn1_write_GeneralString(req, princ_part1);
        }
        
-       asn1_write_GeneralString(&req, princ_part2);
-       asn1_pop_tag(&req);
-       asn1_pop_tag(&req);
-       asn1_pop_tag(&req);
-       asn1_pop_tag(&req);
+       asn1_write_GeneralString(req, princ_part2);
+       asn1_pop_tag(req);
+       asn1_pop_tag(req);
+       asn1_pop_tag(req);
+       asn1_pop_tag(req);
 
-       asn1_push_tag(&req, ASN1_CONTEXT(2));
-       asn1_write_GeneralString(&req, realm);
-       asn1_pop_tag(&req);
-       asn1_pop_tag(&req);
+       asn1_push_tag(req, ASN1_CONTEXT(2));
+       asn1_write_GeneralString(req, realm);
+       asn1_pop_tag(req);
+       asn1_pop_tag(req);
 
-       ret = data_blob(req.data, req.length);
-       asn1_free(&req);
+       ret = data_blob(req->data, req->length);
+       asn1_free(req);
 
        free(princ);
 
@@ -137,7 +140,7 @@ static krb5_error_code build_kpasswd_request(uint16 pversion,
                                           krb5_data *ap_req,
                                           const char *princ,
                                           const char *passwd,
-                                          BOOL use_tcp,
+                                          bool use_tcp,
                                           krb5_data *packet)
 {
        krb5_error_code ret;
@@ -268,7 +271,7 @@ static krb5_error_code setpw_result_code_string(krb5_context context,
        }
 }
 static krb5_error_code parse_setpw_reply(krb5_context context,
-                                        BOOL use_tcp,
+                                        bool use_tcp,
                                         krb5_auth_context auth_context,
                                         krb5_data *packet)
 {
@@ -286,7 +289,7 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
                return KRB5KRB_AP_ERR_MODIFIED;
        }
        
-       p = packet->data;
+       p = (char *)packet->data;
        /*
        ** see if it is an error
        */
@@ -369,7 +372,7 @@ static krb5_error_code parse_setpw_reply(krb5_context context,
                return KRB5KRB_AP_ERR_MODIFIED;
        }
        
-       p = clearresult.data;
+       p = (char *)clearresult.data;
        
        res_code = RSVAL(p, 0);
        
@@ -402,12 +405,15 @@ static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
        krb5_data ap_req, chpw_req, chpw_rep;
        int ret, sock;
        socklen_t addr_len;
-       struct sockaddr remote_addr, local_addr;
-       struct in_addr *addr = interpret_addr2(kdc_host);
+       struct sockaddr_storage remote_addr, local_addr;
+       struct sockaddr_storage addr;
        krb5_address local_kaddr, remote_kaddr;
-       BOOL    use_tcp = False;
+       bool use_tcp = False;
 
 
+       if (!interpret_string_addr(&addr, kdc_host, 0)) {
+       }
+
        ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
                                   NULL, credsp, &ap_req);
        if (ret) {
@@ -420,30 +426,55 @@ static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
                if (!use_tcp) {
 
                        sock = open_udp_socket(kdc_host, DEFAULT_KPASSWD_PORT);
-
+                       if (sock == -1) {
+                               int rc = errno;
+                               SAFE_FREE(ap_req.data);
+                               krb5_auth_con_free(context, auth_context);
+                               DEBUG(1,("failed to open kpasswd socket to %s "
+                                        "(%s)\n", kdc_host, strerror(errno)));
+                               return ADS_ERROR_SYSTEM(rc);
+                       }
                } else {
-
-                       sock = open_socket_out(SOCK_STREAM, addr, DEFAULT_KPASSWD_PORT, 
-                                              LONG_CONNECT_TIMEOUT);
+                       NTSTATUS status;
+                       status = open_socket_out(&addr, DEFAULT_KPASSWD_PORT,
+                                                LONG_CONNECT_TIMEOUT, &sock);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               SAFE_FREE(ap_req.data);
+                               krb5_auth_con_free(context, auth_context);
+                               DEBUG(1,("failed to open kpasswd socket to %s "
+                                        "(%s)\n", kdc_host,
+                                        nt_errstr(status)));
+                               return ADS_ERROR_NT(status);
+                       }
                }
 
-               if (sock == -1) {
-                       int rc = errno;
+               addr_len = sizeof(remote_addr);
+               if (getpeername(sock, (struct sockaddr *)&remote_addr, &addr_len) != 0) {
+                       close(sock);
                        SAFE_FREE(ap_req.data);
                        krb5_auth_con_free(context, auth_context);
-                       DEBUG(1,("failed to open kpasswd socket to %s (%s)\n", 
-                                kdc_host, strerror(errno)));
-                       return ADS_ERROR_SYSTEM(rc);
+                       DEBUG(1,("getpeername() failed (%s)\n", error_message(errno)));
+                       return ADS_ERROR_SYSTEM(errno);
                }
-               
-               addr_len = sizeof(remote_addr);
-               getpeername(sock, &remote_addr, &addr_len);
                addr_len = sizeof(local_addr);
-               getsockname(sock, &local_addr, &addr_len);
-               
-               setup_kaddr(&remote_kaddr, &remote_addr);
-               setup_kaddr(&local_kaddr, &local_addr);
-       
+               if (getsockname(sock, (struct sockaddr *)&local_addr, &addr_len) != 0) {
+                       close(sock);
+                       SAFE_FREE(ap_req.data);
+                       krb5_auth_con_free(context, auth_context);
+                       DEBUG(1,("getsockname() failed (%s)\n", error_message(errno)));
+                       return ADS_ERROR_SYSTEM(errno);
+               }
+               if (!setup_kaddr(&remote_kaddr, &remote_addr) ||
+                               !setup_kaddr(&local_kaddr, &local_addr)) {
+                       DEBUG(1,("do_krb5_kpasswd_request: "
+                               "Failed to setup addresses.\n"));
+                       close(sock);
+                       SAFE_FREE(ap_req.data);
+                       krb5_auth_con_free(context, auth_context);
+                       errno = EINVAL;
+                       return ADS_ERROR_SYSTEM(EINVAL);
+               }
+
                ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr, NULL);
                if (ret) {
                        close(sock);
@@ -452,7 +483,7 @@ static ADS_STATUS do_krb5_kpasswd_request(krb5_context context,
                        DEBUG(1,("krb5_auth_con_setaddrs failed (%s)\n", error_message(ret)));
                        return ADS_ERROR_KRB5(ret);
                }
-       
+
                ret = build_kpasswd_request(pversion, context, auth_context, &ap_req,
                                          princ, newpw, use_tcp, &chpw_req);
                if (ret) {
@@ -582,7 +613,13 @@ ADS_STATUS ads_krb5_set_password(const char *kdc_host, const char *princ,
        }
        realm++;
 
-       asprintf(&princ_name, "kadmin/changepw@%s", realm);
+       if (asprintf(&princ_name, "kadmin/changepw@%s", realm) == -1) {
+               krb5_cc_close(context, ccache);
+                krb5_free_context(context);
+               DEBUG(1,("asprintf failed\n"));
+               return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
+
        ret = smb_krb5_parse_name(context, princ_name, &creds.server);
        if (ret) {
                krb5_cc_close(context, ccache);
@@ -667,8 +704,10 @@ kerb_prompter(krb5_context ctx, void *data,
        memset(prompts[0].reply->data, 0, prompts[0].reply->length);
        if (prompts[0].reply->length > 0) {
                if (data) {
-                       strncpy(prompts[0].reply->data, data, prompts[0].reply->length-1);
-                       prompts[0].reply->length = strlen(prompts[0].reply->data);
+                       strncpy((char *)prompts[0].reply->data,
+                               (const char *)data,
+                               prompts[0].reply->length-1);
+                       prompts[0].reply->length = strlen((const char *)prompts[0].reply->data);
                } else {
                        prompts[0].reply->length = 0;
                }
@@ -711,8 +750,13 @@ static ADS_STATUS ads_krb5_chg_password(const char *kdc_host,
     krb5_get_init_creds_opt_set_proxiable(&opts, 0);
 
     /* We have to obtain an INITIAL changepw ticket for changing password */
-    asprintf(&chpw_princ, "kadmin/changepw@%s",
-                               (char *) krb5_princ_realm(context, princ));
+    if (asprintf(&chpw_princ, "kadmin/changepw@%s",
+                               (char *) krb5_princ_realm(context, princ)) == -1) {
+       krb5_free_context(context);
+       DEBUG(1,("ads_krb5_chg_password: asprintf fail\n"));
+       return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+    }
+
     password = SMB_STRDUP(oldpw);
     ret = krb5_get_init_creds_password(context, &creds, princ, password,
                                           kerb_prompter, NULL, 
@@ -782,16 +826,14 @@ ADS_STATUS ads_set_machine_password(ADS_STRUCT *ads,
          as otherwise the server might end up setting the password for a user
          instead
         */
-       asprintf(&principal, "%s@%s", machine_account, ads->config.realm);
+       if (asprintf(&principal, "%s@%s", machine_account, ads->config.realm) < 0) {
+               return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        
        status = ads_krb5_set_password(ads->auth.kdc_server, principal, 
                                       password, ads->auth.time_offset);
        
-       free(principal);
-
+       SAFE_FREE(principal);
        return status;
 }
-
-
-
 #endif