예제 #1
0
static NTSTATUS gensec_krb5_wrap(struct gensec_security *gensec_security, 
				   TALLOC_CTX *mem_ctx, 
				   const DATA_BLOB *in, 
				   DATA_BLOB *out)
{
	struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
	krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
	krb5_auth_context auth_context = gensec_krb5_state->auth_context;
	krb5_error_code ret;
	krb5_data input, output;
	input.length = in->length;
	input.data = in->data;
	
	if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
		ret = krb5_mk_priv(context, auth_context, &input, &output, NULL);
		if (ret) {
			DEBUG(1, ("krb5_mk_priv failed: %s\n", 
				  smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
							     ret, mem_ctx)));
			return NT_STATUS_ACCESS_DENIED;
		}
		*out = data_blob_talloc(mem_ctx, output.data, output.length);
		
		krb5_data_free(&output);
	} else {
		return NT_STATUS_ACCESS_DENIED;
	}
	return NT_STATUS_OK;
}
예제 #2
0
kadm5_ret_t 
_kadm5_client_send(kadm5_client_context *context, krb5_storage *sp)
{
    krb5_data msg, out;
    krb5_error_code ret;
    size_t len;
    krb5_storage *sock;

    assert(context->sock != -1);

    len = krb5_storage_seek(sp, 0, SEEK_CUR);
    ret = krb5_data_alloc(&msg, len);
    if (ret)
	return ret;
    krb5_storage_seek(sp, 0, SEEK_SET);
    krb5_storage_read(sp, msg.data, msg.length);
    
    ret = krb5_mk_priv(context->context, context->ac, &msg, &out, NULL);
    krb5_data_free(&msg);
    if(ret)
	return ret;
    
    sock = krb5_storage_from_fd(context->sock);
    if(sock == NULL) {
	krb5_data_free(&out);
	return ENOMEM;
    }
    
    ret = krb5_store_data(sock, out);
    krb5_storage_free(sock);
    krb5_data_free(&out);
    return ret;
}
예제 #3
0
static void
reply_priv (krb5_auth_context auth_context,
            int s,
            struct sockaddr *sa,
            int sa_size,
            uint16_t result_code,
            const char *expl)
{
    krb5_error_code ret;
    krb5_data krb_priv_data;
    krb5_data ap_rep_data;
    krb5_data e_data;

    ret = krb5_mk_rep (context,
                       auth_context,
                       &ap_rep_data);
    if (ret) {
        krb5_warn (context, ret, "Could not even generate error reply");
        return;
    }

    if (make_result(&e_data, result_code, expl))
        return;

    ret = krb5_mk_priv (context,
                        auth_context,
                        &e_data,
                        &krb_priv_data,
                        NULL);
    krb5_data_free (&e_data);
    if (ret) {
        krb5_warn (context, ret, "Could not even generate error reply");
        return;
    }
    send_reply (s, sa, sa_size, &ap_rep_data, &krb_priv_data);
    krb5_data_free (&ap_rep_data);
    krb5_data_free (&krb_priv_data);
}
예제 #4
0
파일: kprop.c 프로젝트: Akasurde/krb5
/*
 * Now we send over the database.  We use the following protocol:
 * Send over a KRB_SAFE message with the size.  Then we send over the
 * database in blocks of KPROP_BLKSIZE, encrypted using KRB_PRIV.
 * Then we expect to see a KRB_SAFE message with the size sent back.
 *
 * At any point in the protocol, we may send a KRB_ERROR message; this
 * will abort the entire operation.
 */
static void
xmit_database(krb5_context context, krb5_auth_context auth_context,
              krb5_creds *my_creds, int fd, int database_fd,
              int in_database_size)
{
    krb5_int32 n;
    krb5_data inbuf, outbuf;
    char buf[KPROP_BUFSIZ];
    krb5_error_code retval;
    krb5_error *error;
    krb5_ui_4 database_size = in_database_size, send_size, sent_size;

    /* Send over the size. */
    send_size = htonl(database_size);
    inbuf.data = (char *)&send_size;
    inbuf.length = sizeof(send_size); /* must be 4, really */
    /* KPROP_CKSUMTYPE */
    retval = krb5_mk_safe(context, auth_context, &inbuf, &outbuf, NULL);
    if (retval) {
        com_err(progname, retval, _("while encoding database size"));
        send_error(context, my_creds, fd, _("while encoding database size"),
                   retval);
        exit(1);
    }

    retval = krb5_write_message(context, &fd, &outbuf);
    if (retval) {
        krb5_free_data_contents(context, &outbuf);
        com_err(progname, retval, _("while sending database size"));
        exit(1);
    }
    krb5_free_data_contents(context, &outbuf);

    /* Initialize the initial vector. */
    retval = krb5_auth_con_initivector(context, auth_context);
    if (retval) {
        send_error(context, my_creds, fd,
                   "failed while initializing i_vector", retval);
        com_err(progname, retval, _("while allocating i_vector"));
        exit(1);
    }

    /* Send over the file, block by block. */
    inbuf.data = buf;
    sent_size = 0;
    while ((n = read(database_fd, buf, sizeof(buf)))) {
        inbuf.length = n;
        retval = krb5_mk_priv(context, auth_context, &inbuf, &outbuf, NULL);
        if (retval) {
            snprintf(buf, sizeof(buf),
                     "while encoding database block starting at %d",
                     sent_size);
            com_err(progname, retval, "%s", buf);
            send_error(context, my_creds, fd, buf, retval);
            exit(1);
        }

        retval = krb5_write_message(context, &fd, &outbuf);
        if (retval) {
            krb5_free_data_contents(context, &outbuf);
            com_err(progname, retval,
                    _("while sending database block starting at %d"),
                    sent_size);
            exit(1);
        }
        krb5_free_data_contents(context, &outbuf);
        sent_size += n;
        if (debug)
            printf("%d bytes sent.\n", sent_size);
    }
    if (sent_size != database_size) {
        com_err(progname, 0, _("Premature EOF found for database file!"));
        send_error(context, my_creds, fd,
                   "Premature EOF found for database file!",
                   KRB5KRB_ERR_GENERIC);
        exit(1);
    }

    /*
     * OK, we've sent the database; now let's wait for a success
     * indication from the remote end.
     */
    retval = krb5_read_message(context, &fd, &inbuf);
    if (retval) {
        com_err(progname, retval, _("while reading response from server"));
        exit(1);
    }
    /*
     * If we got an error response back from the server, display
     * the error message
     */
    if (krb5_is_krb_error(&inbuf)) {
        retval = krb5_rd_error(context, &inbuf, &error);
        if (retval) {
            com_err(progname, retval,
                    _("while decoding error response from server"));
            exit(1);
        }
        if (error->error == KRB_ERR_GENERIC) {
            if (error->text.data) {
                fprintf(stderr, _("Generic remote error: %s\n"),
                        error->text.data);
            }
        } else if (error->error) {
            com_err(progname,
                    (krb5_error_code)error->error + ERROR_TABLE_BASE_krb5,
                    _("signalled from server"));
            if (error->text.data) {
                fprintf(stderr, _("Error text from server: %s\n"),
                        error->text.data);
            }
        }
        krb5_free_error(context, error);
        exit(1);
    }

    retval = krb5_rd_safe(context,auth_context,&inbuf,&outbuf,NULL);
    if (retval) {
        com_err(progname, retval,
                "while decoding final size packet from server");
        exit(1);
    }

    memcpy(&send_size, outbuf.data, sizeof(send_size));
    send_size = ntohl(send_size);
    if (send_size != database_size) {
        com_err(progname, 0, _("Kpropd sent database size %d, expecting %d"),
                send_size, database_size);
        exit(1);
    }
    free(outbuf.data);
}
예제 #5
0
static int
proto (int sock, const char *hostname, const char *service)
{
    struct sockaddr_in remote, local;
    socklen_t addrlen;
    krb5_address remote_addr, local_addr;
    krb5_context context;
    krb5_ccache ccache;
    krb5_auth_context auth_context;
    krb5_error_code status;
    krb5_principal client;
    krb5_data data;
    krb5_data packet;
    krb5_creds mcred, cred;
    krb5_ticket *ticket;

    addrlen = sizeof(local);
    if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
	|| addrlen != sizeof(local))
	err (1, "getsockname(%s)", hostname);

    addrlen = sizeof(remote);
    if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
	|| addrlen != sizeof(remote))
	err (1, "getpeername(%s)", hostname);

    status = krb5_init_context(&context);
    if (status)
	errx(1, "krb5_init_context failed: %d", status);

    status = krb5_cc_default (context, &ccache);
    if (status)
	krb5_err(context, 1, status, "krb5_cc_default");

    status = krb5_auth_con_init (context, &auth_context);
    if (status)
	krb5_err(context, 1, status, "krb5_auth_con_init");

    local_addr.addr_type = AF_INET;
    local_addr.address.length = sizeof(local.sin_addr);
    local_addr.address.data   = &local.sin_addr;

    remote_addr.addr_type = AF_INET;
    remote_addr.address.length = sizeof(remote.sin_addr);
    remote_addr.address.data   = &remote.sin_addr;

    status = krb5_auth_con_setaddrs (context,
				     auth_context,
				     &local_addr,
				     &remote_addr);
    if (status)
	krb5_err(context, 1, status, "krb5_auth_con_setaddr");

    krb5_cc_clear_mcred(&mcred);

    status = krb5_cc_get_principal(context, ccache, &client);
    if(status)
	krb5_err(context, 1, status, "krb5_cc_get_principal");
    status = krb5_make_principal(context, &mcred.server,
				 krb5_principal_get_realm(context, client),
				 "krbtgt",
				 krb5_principal_get_realm(context, client),
				 NULL);
    if(status)
	krb5_err(context, 1, status, "krb5_make_principal");
    mcred.client = client;

    status = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
    if(status)
	krb5_err(context, 1, status, "krb5_cc_retrieve_cred");

    {
	char *client_name;
	krb5_data data;
	status = krb5_unparse_name(context, cred.client, &client_name);
	if(status)
	    krb5_err(context, 1, status, "krb5_unparse_name");
	data.data = client_name;
	data.length = strlen(client_name) + 1;
	status = krb5_write_message(context, &sock, &data);
	if(status)
	    krb5_err(context, 1, status, "krb5_write_message");
	free(client_name);
    }

    status = krb5_write_message(context, &sock, &cred.ticket);
    if(status)
	krb5_err(context, 1, status, "krb5_write_message");

    status = krb5_auth_con_setuserkey(context, auth_context, &cred.session);
    if(status)
	krb5_err(context, 1, status, "krb5_auth_con_setuserkey");

    status = krb5_recvauth(context, &auth_context, &sock,
			   VERSION, client, 0, NULL, &ticket);

    if (status)
	krb5_err(context, 1, status, "krb5_recvauth");

    if (ticket->ticket.authorization_data) {
	AuthorizationData *authz;
	int i;

	printf("Authorization data:\n");

	authz = ticket->ticket.authorization_data;
	for (i = 0; i < authz->len; i++) {
	    printf("\ttype %d, length %lu\n",
		   authz->val[i].ad_type,
		   (unsigned long)authz->val[i].ad_data.length);
	}
    }

    data.data   = "hej";
    data.length = 3;

    krb5_data_zero (&packet);

    status = krb5_mk_safe (context,
			   auth_context,
			   &data,
			   &packet,
			   NULL);
    if (status)
	krb5_err(context, 1, status, "krb5_mk_safe");

    status = krb5_write_message(context, &sock, &packet);
    if(status)
	krb5_err(context, 1, status, "krb5_write_message");

    data.data   = "hemligt";
    data.length = 7;

    krb5_data_free (&packet);

    status = krb5_mk_priv (context,
			   auth_context,
			   &data,
			   &packet,
			   NULL);
    if (status)
	krb5_err(context, 1, status, "krb5_mk_priv");

    status = krb5_write_message(context, &sock, &packet);
    if(status)
	krb5_err(context, 1, status, "krb5_write_message");
    return 0;
}
예제 #6
0
static int
proto (int sock, const char *hostname, const char *service)
{
    krb5_auth_context auth_context;
    krb5_error_code status;
    krb5_principal server;
    krb5_data data;
    krb5_data packet;
    u_int32_t len, net_len;

    status = krb5_auth_con_init (context, &auth_context);
    if (status)
	krb5_err (context, 1, status, "krb5_auth_con_init");

    status = krb5_auth_con_setaddrs_from_fd (context,
					     auth_context,
					     &sock);
    if (status)
	krb5_err (context, 1, status, "krb5_auth_con_setaddrs_from_fd");

    status = krb5_sname_to_principal (context,
				      hostname,
				      service,
				      KRB5_NT_SRV_HST,
				      &server);
    if (status)
	krb5_err (context, 1, status, "krb5_sname_to_principal");

    status = krb5_sendauth (context,
			    &auth_context,
			    &sock,
			    VERSION,
			    NULL,
			    server,
			    AP_OPTS_MUTUAL_REQUIRED,
			    NULL,
			    NULL,
			    NULL,
			    NULL,
			    NULL,
			    NULL);
    if (status)
	krb5_err (context, 1, status, "krb5_sendauth");

    data.data   = "hej";
    data.length = 3;

    krb5_data_zero (&packet);

    status = krb5_mk_safe (context,
			   auth_context,
			   &data,
			   &packet,
			   NULL);
    if (status)
	krb5_err (context, 1, status, "krb5_mk_safe");

    len = packet.length;
    net_len = htonl(len);

    if (krb5_net_write (context, &sock, &net_len, 4) != 4)
	err (1, "krb5_net_write");
    if (krb5_net_write (context, &sock, packet.data, len) != len)
	err (1, "krb5_net_write");

    data.data   = "hemligt";
    data.length = 7;

    krb5_data_free (&packet);

    status = krb5_mk_priv (context,
			   auth_context,
			   &data,
			   &packet,
			   NULL);
    if (status)
	krb5_err (context, 1, status, "krb5_mk_priv");

    len = packet.length;
    net_len = htonl(len);

    if (krb5_net_write (context, &sock, &net_len, 4) != 4)
	err (1, "krb5_net_write");
    if (krb5_net_write (context, &sock, packet.data, len) != len)
	err (1, "krb5_net_write");
    return 0;
}
예제 #7
0
파일: afsadmd.c 프로젝트: Majlen/afsadm
int do_krb5_comm(krb5_context context, krb5_keytab keytab, krb5_principal server, char *cmddir) {
	struct sockaddr_in c_saddr, s_saddr;
	socklen_t namelen;
	int sock = 0;
	int len;
	char buff[BUFFSIZE];
	char *cname = NULL;
	krb5_error_code retval;
	krb5_data kdata, message;
	krb5_auth_context auth_context = NULL;
	krb5_ticket *ticket;
	krb5_address ckaddr, skaddr;
	krb5_rcache rcache;
	krb5_data rcache_name;
	long srand, rrand;
	int fd[2];
	char rcname_piece[RC_PIECE_MAXLEN];

	namelen = sizeof(c_saddr);
	if (getpeername(sock, (struct sockaddr *)&c_saddr, &namelen) < 0) {
		syslog(LOG_ERR, "getpeername: %m");
		return 1;
	}

	namelen = sizeof(s_saddr);
	if (getsockname(sock, (struct sockaddr *)&s_saddr, &namelen) < 0) {
		syslog(LOG_ERR, "getsockname: %m");
		return 1;
	}

	/* INIT MSG = random number */
	srand = random();

	/* Send it */
	if (send(sock, &srand, sizeof(srand), 0) < 0) {
		syslog(LOG_ERR, "%m while sending init message");
		return 1;
	}
	if (recv(sock, &rrand, sizeof(rrand), 0) < 0) {
		syslog(LOG_ERR, "%m while receiving init reply");
		return 1;
	}

	/* Reply should contain the same message (number) */
	if (srand != rrand) {
		syslog(LOG_ERR, "Bad init reply");
		return 1;
	}

	/* Do authentication */
	if (retval = krb5_recvauth(context, &auth_context, (krb5_pointer)&sock, AFSADM_VERSION, server, 0, keytab, &ticket)) {
		syslog(LOG_ERR, "recvauth failed: %s", error_message(retval));
		exit(1);
	}

	/* Get client name */
	if (retval = krb5_unparse_name(context, ticket->enc_part2->client, &cname)) {
		syslog(LOG_ERR, "unparse failed: %s", error_message(retval));
		return 1;
	}

	if (ticket)
		krb5_free_ticket(context, ticket);

	if (debug)
		syslog(LOG_DEBUG, "Principal %s", cname);

	/*******************************************************************/

	ckaddr.addrtype = ADDRTYPE_IPPORT;
	ckaddr.length   = sizeof(c_saddr.sin_port);
	ckaddr.contents = (krb5_octet *)&c_saddr.sin_port;

	skaddr.addrtype = ADDRTYPE_IPPORT;
	skaddr.length   = sizeof(s_saddr.sin_port);
	skaddr.contents = (krb5_octet *)&s_saddr.sin_port;
	if ((retval = krb5_auth_con_setports(context, auth_context, &skaddr, &ckaddr))) {
		syslog(LOG_ERR, "%s while setting ports", error_message(retval));
		return 1;
	}

	/* Set foreign_addr for rd_priv() */
	ckaddr.addrtype = ADDRTYPE_INET;
	ckaddr.length   = sizeof(c_saddr.sin_addr);
	ckaddr.contents = (krb5_octet *)&c_saddr.sin_addr;

	/* Set local_addr  */
	skaddr.addrtype = ADDRTYPE_INET;
	skaddr.length   = sizeof(s_saddr.sin_addr);
	skaddr.contents = (krb5_octet *)&s_saddr.sin_addr;

	if ((retval = krb5_auth_con_setaddrs(context, auth_context, &skaddr, &ckaddr))) {
		syslog(LOG_ERR, "%s while setting addrs", error_message(retval));
		return 1;
	}

	/* Receive a request */
	if ((len = recv(sock, (char *)buff, sizeof(buff), 0)) < 0) {
		syslog(LOG_ERR, "%m while receiving datagram");
		return 1;
	}

	kdata.length = len;
	kdata.data = buff;

	if (debug)
		syslog(LOG_DEBUG, "Received %d bytes", len);

	/* Decrypt it */
	if ((retval = krb5_rd_priv(context, auth_context, &kdata, &message, NULL))) {
		syslog(LOG_ERR, "%s while verifying PRIV message", error_message(retval));
		return 1;
	}

	if (message.length > 0) {
#ifdef __osf__
		sprintf(rcname_piece, "afsadmd_%d",  getpid());
#else
		snprintf(rcname_piece, RC_PIECE_MAXLEN, "afsadmd_%d", getpid());
#endif
		rcache_name.data = rcname_piece;
		rcache_name.length = strlen(rcache_name.data);

		if ((retval = krb5_get_server_rcache(context, &rcache_name, &rcache))) {
			syslog(LOG_ERR, "%s while getting server rcache", error_message(retval));
			return 1;
		}

		/* set auth_context rcache */
		if (retval = krb5_auth_con_setrcache(context, auth_context, rcache)) {
			syslog(LOG_ERR, "%s while setting rcache", error_message(retval));
			return 1;
		}

		/*********************************************************************
		 * Call the desired command, read stdout/stderr, send it
		 *********************************************************************/

		/* create fork */
		if (pipe(fd) == -1)
			printf("Failed create fork with pipe().\n");

		if (fork() == 0) {
			close(fd[0]);
			close(1);
			close(2);
			dup2(fd[1], 1);
			dup2(fd[1], 2);

			/* Call required command */
			do_command(context, keytab, server, cname, message.data, cmddir );
			krb5_xfree(message.data);
			exit(0);
		} else {
			/* Read stdout/stderr from pipe, store it to the buffer, encrypt it a send to the client */
			krb5_data message, kdata;
			char buff[PIPEBUFF];
			int n = 0;
			int len = 0;
			int sent = 0;
			int counter = 0;
			int end = 0;
			short netlen;
			time_t starttime, oldtime, newtime;
			FILE *pipedes;

			close(fd[1]);
			pipedes = fdopen(fd[0], "r");

			starttime = oldtime = time(NULL);

			for (n = 0; end == 0; ) {
				/* Read line from pipe */
				if (fgets(buff + n, PIPEBUFF - n, pipedes) == NULL)
					end++;
				else
					n = strlen(buff);

				/* Get time */
				newtime = time(NULL);

				/* Send buffer when
				 *    a) buffer is full
				 *    b) buffer contains data and
				 *      1) end-of-file encountered (end flag)
				 *      2) buffer sent before 1s
				 */
				if ((n == PIPEBUFF) || (((newtime > oldtime) || end ) && (n != 0))) {
					/* Prepare data for sending */
					message.data = buff;
					message.length = n;
					kdata.data = NULL;

					/* Make the encrypted message */
					if ((retval = krb5_mk_priv(context, auth_context, &message, &kdata, NULL))) {
						syslog(LOG_ERR, "%s while making KRB_PRIV message", error_message(retval));
						return 1;
					}

					/* Convert byte order */
					netlen = htons((short)kdata.length);

					/* Send len of encrypted data */
					if ((len = send(sock, (char *)&netlen, sizeof(netlen), 0)) != sizeof(netlen)) {
						krb5_xfree(kdata.data);
						syslog(LOG_ERR, "%m while sending len of PRIV message");
						return 1;
					}

					/* Send it */
					if ((len = send(sock, (char *)kdata.data, kdata.length, 0)) != kdata.length) {
						syslog(LOG_ERR, "%m while sending PRIV message");
						krb5_xfree(kdata.data);
						return 1;
					}

					/* Statistics */
					sent += len;
					counter++;

					/* Timestanmp */
					oldtime = newtime;
					n = 0;

					krb5_xfree(kdata.data);
				}
			}

			newtime = time(NULL);

			if (debug)
				syslog(LOG_DEBUG, "Sent %d bytes in %ds [%d fragment(s)]", sent, (int)(newtime - starttime),  counter);
		}
	}

	//FIXME: There is no way to close or destroy rcache declared in krb5 headers
	//krb5_rc_destroy(context, rcache);

	/* set auth_context rcache */
	if (retval = krb5_auth_con_setrcache(context, auth_context, rcache)) {
		syslog(LOG_ERR, "%s while setting rcache to NULL", error_message(retval));
		return 1;
	}

	free(cname);
	krb5_auth_con_free(context, auth_context);
	return 0;
}
예제 #8
0
static krb5_error_code
chgpw_send_request (krb5_context context,
		    krb5_auth_context *auth_context,
		    krb5_creds *creds,
		    krb5_principal targprinc,
		    int is_stream,
		    int sock,
		    char *passwd,
		    const char *host)
{
    krb5_error_code ret;
    krb5_data ap_req_data;
    krb5_data krb_priv_data;
    krb5_data passwd_data;
    size_t len;
    u_char header[6];
    u_char *p;
    struct iovec iov[3];
    struct msghdr msghdr;

    if (is_stream)
	return KRB5_KPASSWD_MALFORMED;

    if (targprinc &&
	krb5_principal_compare(context, creds->client, targprinc) != TRUE)
	return KRB5_KPASSWD_MALFORMED;

    krb5_data_zero (&ap_req_data);

    ret = krb5_mk_req_extended (context,
				auth_context,
				AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
				NULL, /* in_data */
				creds,
				&ap_req_data);
    if (ret)
	return ret;

    passwd_data.data   = passwd;
    passwd_data.length = strlen(passwd);

    krb5_data_zero (&krb_priv_data);

    ret = krb5_mk_priv (context,
			*auth_context,
			&passwd_data,
			&krb_priv_data,
			NULL);
    if (ret)
	goto out2;

    len = 6 + ap_req_data.length + krb_priv_data.length;
    p = header;
    *p++ = (len >> 8) & 0xFF;
    *p++ = (len >> 0) & 0xFF;
    *p++ = 0;
    *p++ = 1;
    *p++ = (ap_req_data.length >> 8) & 0xFF;
    *p++ = (ap_req_data.length >> 0) & 0xFF;

    memset(&msghdr, 0, sizeof(msghdr));
    msghdr.msg_name       = NULL;
    msghdr.msg_namelen    = 0;
    msghdr.msg_iov        = iov;
    msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
#if 0
    msghdr.msg_control    = NULL;
    msghdr.msg_controllen = 0;
#endif

    iov[0].iov_base    = (void*)header;
    iov[0].iov_len     = 6;
    iov[1].iov_base    = ap_req_data.data;
    iov[1].iov_len     = ap_req_data.length;
    iov[2].iov_base    = krb_priv_data.data;
    iov[2].iov_len     = krb_priv_data.length;

    if (sendmsg (sock, &msghdr, 0) < 0) {
	ret = errno;
	krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret));
    }

    krb5_data_free (&krb_priv_data);
out2:
    krb5_data_free (&ap_req_data);
    return ret;
}
예제 #9
0
static krb5_error_code
setpw_send_request (krb5_context context,
		    krb5_auth_context *auth_context,
		    krb5_creds *creds,
		    krb5_principal targprinc,
		    int is_stream,
		    int sock,
		    char *passwd,
		    const char *host)
{
    krb5_error_code ret;
    krb5_data ap_req_data;
    krb5_data krb_priv_data;
    krb5_data pwd_data;
    ChangePasswdDataMS chpw;
    size_t len;
    u_char header[4 + 6];
    u_char *p;
    struct iovec iov[3];
    struct msghdr msghdr;

    krb5_data_zero (&ap_req_data);

    ret = krb5_mk_req_extended (context,
				auth_context,
				AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
				NULL, /* in_data */
				creds,
				&ap_req_data);
    if (ret)
	return ret;

    chpw.newpasswd.length = strlen(passwd);
    chpw.newpasswd.data = passwd;
    if (targprinc) {
	chpw.targname = &targprinc->name;
	chpw.targrealm = &targprinc->realm;
    } else {
	chpw.targname = NULL;
	chpw.targrealm = NULL;
    }
	
    ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
		       &chpw, &len, ret);
    if (ret) {
	krb5_data_free (&ap_req_data);
	return ret;
    }

    if(pwd_data.length != len)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_mk_priv (context,
			*auth_context,
			&pwd_data,
			&krb_priv_data,
			NULL);
    if (ret)
	goto out2;

    len = 6 + ap_req_data.length + krb_priv_data.length;
    p = header;
    if (is_stream) {
	_krb5_put_int(p, len, 4);
	p += 4;
    }
    *p++ = (len >> 8) & 0xFF;
    *p++ = (len >> 0) & 0xFF;
    *p++ = 0xff;
    *p++ = 0x80;
    *p++ = (ap_req_data.length >> 8) & 0xFF;
    *p++ = (ap_req_data.length >> 0) & 0xFF;

    memset(&msghdr, 0, sizeof(msghdr));
    msghdr.msg_name       = NULL;
    msghdr.msg_namelen    = 0;
    msghdr.msg_iov        = iov;
    msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
#if 0
    msghdr.msg_control    = NULL;
    msghdr.msg_controllen = 0;
#endif

    iov[0].iov_base    = (void*)header;
    if (is_stream)
	iov[0].iov_len     = 10;
    else
	iov[0].iov_len     = 6;
    iov[1].iov_base    = ap_req_data.data;
    iov[1].iov_len     = ap_req_data.length;
    iov[2].iov_base    = krb_priv_data.data;
    iov[2].iov_len     = krb_priv_data.length;

    if (sendmsg (sock, &msghdr, 0) < 0) {
	ret = errno;
	krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret));
    }

    krb5_data_free (&krb_priv_data);
out2:
    krb5_data_free (&ap_req_data);
    krb5_data_free (&pwd_data);
    return ret;
}
예제 #10
0
static krb5_error_code build_kpasswd_request(uint16 pversion,
					   krb5_context context,
					   krb5_auth_context auth_context,
					   krb5_data *ap_req,
					   const char *princ,
					   const char *passwd,
					   bool use_tcp,
					   krb5_data *packet)
{
	krb5_error_code ret;
	krb5_data cipherpw;
	krb5_data encoded_setpw;
	krb5_replay_data replay;
	char *p, *msg_start;
	DATA_BLOB setpw;
	unsigned int msg_length;

	ret = krb5_auth_con_setflags(context,
				     auth_context,KRB5_AUTH_CONTEXT_DO_SEQUENCE);
	if (ret) {
		DEBUG(1,("krb5_auth_con_setflags failed (%s)\n",
			 error_message(ret)));
		return ret;
	}

	/* handle protocol differences in chpw and setpw */
	if (pversion  == KRB5_KPASSWD_VERS_CHANGEPW)
		setpw = data_blob(passwd, strlen(passwd));
	else if (pversion == KRB5_KPASSWD_VERS_SETPW ||
		 pversion == KRB5_KPASSWD_VERS_SETPW_ALT)
		setpw = encode_krb5_setpw(princ, passwd);
	else
		return EINVAL;

	if (setpw.data == NULL || setpw.length == 0) {
		return EINVAL;
	}

	encoded_setpw.data = (char *)setpw.data;
	encoded_setpw.length = setpw.length;

	ret = krb5_mk_priv(context, auth_context,
			   &encoded_setpw, &cipherpw, &replay);
	
	data_blob_free(&setpw); 	/*from 'encode_krb5_setpw(...)' */
	
	if (ret) {
		DEBUG(1,("krb5_mk_priv failed (%s)\n", error_message(ret)));
		return ret;
	}

	packet->data = (char *)SMB_MALLOC(ap_req->length + cipherpw.length + (use_tcp ? 10 : 6 ));
	if (!packet->data)
		return -1;



	/* see the RFC for details */

	msg_start = p = ((char *)packet->data) + (use_tcp ? 4 : 0);
	p += 2;
	RSSVAL(p, 0, pversion);
	p += 2;
	RSSVAL(p, 0, ap_req->length);
	p += 2;
	memcpy(p, ap_req->data, ap_req->length);
	p += ap_req->length;
	memcpy(p, cipherpw.data, cipherpw.length);
	p += cipherpw.length;
	packet->length = PTR_DIFF(p,packet->data);
	msg_length = PTR_DIFF(p,msg_start);

	if (use_tcp) {
		RSIVAL(packet->data, 0, msg_length);
	}
	RSSVAL(msg_start, 0, msg_length);
	
	free(cipherpw.data);    /* from 'krb5_mk_priv(...)' */

	return 0;
}
예제 #11
0
static krb5_error_code
chgpw_prexmit(krb5_context context, int proto,
              void *ctx, rk_socket_t fd, krb5_data *data)
{
    struct request *request = ctx;
    krb5_data ap_req_data, krb_priv_data, passwd_data;
    krb5_storage *sp = NULL;
    krb5_error_code ret;
    krb5_ssize_t slen;
    size_t len;

    krb5_data_zero(&ap_req_data);
    krb5_data_zero(&krb_priv_data);

    ret = krb5_auth_con_genaddrs(context, request->ac, fd,
                                 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
    if (ret)
        goto out;

    ret = krb5_mk_req_extended(context,
                               &request->ac,
                               AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
                               NULL,
                               request->creds,
                               &ap_req_data);
    if (ret)
        goto out;

    passwd_data.data   = rk_UNCONST(request->password);
    passwd_data.length = strlen(request->password);

    ret = krb5_mk_priv(context,
                       request->ac,
                       &passwd_data,
                       &krb_priv_data,
                       NULL);
    if (ret)
        goto out;

    sp = krb5_storage_emem();
    if (sp == NULL) {
        ret = ENOMEM;
        goto out;
    }

    len = 6 + ap_req_data.length + krb_priv_data.length;

    ret = krb5_store_uint16(sp, len);
    if (ret) goto out;
    ret = krb5_store_uint16(sp, 1);
    if (ret) goto out;
    ret = krb5_store_uint16(sp, ap_req_data.length);
    if (ret) goto out;
    slen = krb5_storage_write(sp, ap_req_data.data, ap_req_data.length);
    if (slen != ap_req_data.length) {
        ret = EINVAL;
        goto out;
    }
    slen = krb5_storage_write(sp, krb_priv_data.data, krb_priv_data.length);
    if (slen != krb_priv_data.length) {
        ret = EINVAL;
        goto out;
    }

    ret = krb5_storage_to_data(sp, data);

out:
    if (ret)
        _krb5_debugx(context, 10, "chgpw_prexmit failed with: %d", ret);
    if (sp)
        krb5_storage_free(sp);
    krb5_data_free(&krb_priv_data);
    krb5_data_free(&ap_req_data);
    return ret;
}
예제 #12
0
static krb5_error_code
setpw_prexmit(krb5_context context, int proto,
              void *ctx, int fd, krb5_data *data)
{
    struct request *request = ctx;
    krb5_data ap_req_data, krb_priv_data, pwd_data;
    krb5_error_code ret;
    ChangePasswdDataMS chpw;
    krb5_storage *sp = NULL;
    ssize_t slen;
    size_t len;

    krb5_data_zero(&ap_req_data);
    krb5_data_zero(&krb_priv_data);
    krb5_data_zero(&pwd_data);

    ret = krb5_auth_con_genaddrs(context, request->ac, fd,
                                 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
    if (ret)
        goto out;

    ret = krb5_mk_req_extended(context,
                               &request->ac,
                               AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
                               NULL,
                               request->creds,
                               &ap_req_data);
    if (ret)
        goto out;

    chpw.newpasswd.length = strlen(request->password);
    chpw.newpasswd.data = rk_UNCONST(request->password);
    if (request->target) {
        chpw.targname = &request->target->name;
        chpw.targrealm = &request->target->realm;
    } else {
        chpw.targname = NULL;
        chpw.targrealm = NULL;
    }

    ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
                       &chpw, &len, ret);
    if (ret)
        goto out;
    if(pwd_data.length != len)
        krb5_abortx(context, "internal error in ASN.1 encoder");

    ret = krb5_mk_priv (context,
                        request->ac,
                        &pwd_data,
                        &krb_priv_data,
                        NULL);
    if (ret)
        goto out;

    sp = krb5_storage_emem();
    if (sp == NULL) {
        ret = ENOMEM;
        goto out;
    }

    len = 6 + ap_req_data.length + krb_priv_data.length;

    ret = krb5_store_uint16(sp, len);
    if (ret) goto out;
    ret = krb5_store_uint16(sp, 0xff80);
    if (ret) goto out;
    ret = krb5_store_uint16(sp, ap_req_data.length);
    if (ret) goto out;
    slen = krb5_storage_write(sp, ap_req_data.data, ap_req_data.length);
    if (slen != ap_req_data.length) {
        ret = EINVAL;
        goto out;
    }
    slen = krb5_storage_write(sp, krb_priv_data.data, krb_priv_data.length);
    if (slen != krb_priv_data.length) {
        ret = EINVAL;
        goto out;
    }

    ret = krb5_storage_to_data(sp, data);

out:
    if (ret)
        _krb5_debugx(context, 10, "setpw_prexmit failed with %d", ret);
    if (sp)
        krb5_storage_free(sp);
    krb5_data_free(&krb_priv_data);
    krb5_data_free(&ap_req_data);
    krb5_data_free(&pwd_data);

    return ret;
}
예제 #13
0
파일: chpw.c 프로젝트: jmoldow/krb5
krb5_error_code
krb5int_mk_setpw_req(krb5_context context,
                     krb5_auth_context auth_context,
                     krb5_data *ap_req,
                     krb5_principal targprinc,
                     char *passwd,
                     krb5_data *packet)
{
    krb5_error_code ret;
    krb5_data   cipherpw;
    krb5_data   *encoded_setpw;
    struct krb5_setpw_req req;

    char *ptr;

    cipherpw.data = NULL;
    cipherpw.length = 0;

    if ((ret = krb5_auth_con_setflags(context, auth_context,
                                      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
        return(ret);

    req.target = targprinc;
    req.password.data = passwd;
    req.password.length = strlen(passwd);
    ret = encode_krb5_setpw_req(&req, &encoded_setpw);
    if (ret) {
        return ret;
    }

    if ((ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
        krb5_free_data(context, encoded_setpw);
        return(ret);
    }
    krb5_free_data(context, encoded_setpw);


    packet->length = 6 + ap_req->length + cipherpw.length;
    packet->data = (char *) malloc(packet->length);
    if (packet->data  == NULL) {
        ret = ENOMEM;
        goto cleanup;
    }
    ptr = packet->data;
    /*
    ** build the packet -
    */
    /* put in the length */
    store_16_be(packet->length, ptr);
    ptr += 2;
    /* put in the version */
    *ptr++ = (char)0xff;
    *ptr++ = (char)0x80;
    /* the ap_req length is big endian */
    store_16_be(ap_req->length, ptr);
    ptr += 2;
    /* put in the request data */
    memcpy(ptr, ap_req->data, ap_req->length);
    ptr += ap_req->length;
    /*
    ** put in the "private" password data -
    */
    memcpy(ptr, cipherpw.data, cipherpw.length);
    ret = 0;
cleanup:
    if (cipherpw.data)
        krb5_free_data_contents(context, &cipherpw);
    if ((ret != 0) && packet->data) {
        free(packet->data);
        packet->data = NULL;
    }
    return ret;
}
예제 #14
0
파일: chpw.c 프로젝트: jmoldow/krb5
krb5_error_code
krb5int_mk_chpw_req(krb5_context context,
                    krb5_auth_context auth_context,
                    krb5_data *ap_req,
                    char *passwd,
                    krb5_data *packet)
{
    krb5_error_code ret = 0;
    krb5_data clearpw;
    krb5_data cipherpw;
    krb5_replay_data replay;
    char *ptr;

    cipherpw.data = NULL;

    if ((ret = krb5_auth_con_setflags(context, auth_context,
                                      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
        goto cleanup;

    clearpw.length = strlen(passwd);
    clearpw.data = passwd;

    if ((ret = krb5_mk_priv(context, auth_context,
                            &clearpw, &cipherpw, &replay)))
        goto cleanup;

    packet->length = 6 + ap_req->length + cipherpw.length;
    packet->data = (char *) malloc(packet->length);
    if (packet->data == NULL) {
        ret = ENOMEM;
        goto cleanup;
    }
    ptr = packet->data;

    /* length */

    store_16_be(packet->length, ptr);
    ptr += 2;

    /* version == 0x0001 big-endian */

    *ptr++ = 0;
    *ptr++ = 1;

    /* ap_req length, big-endian */

    store_16_be(ap_req->length, ptr);
    ptr += 2;

    /* ap-req data */

    memcpy(ptr, ap_req->data, ap_req->length);
    ptr += ap_req->length;

    /* krb-priv of password */

    memcpy(ptr, cipherpw.data, cipherpw.length);

cleanup:
    if (cipherpw.data != NULL)  /* allocated by krb5_mk_priv */
        free(cipherpw.data);

    return(ret);
}
예제 #15
0
파일: schpw.c 프로젝트: Akasurde/krb5
static krb5_error_code
process_chpw_request(krb5_context context, void *server_handle, char *realm,
                     krb5_keytab keytab, const krb5_fulladdr *local_faddr,
                     const krb5_fulladdr *remote_faddr, krb5_data *req,
                     krb5_data *rep)
{
    krb5_error_code ret;
    char *ptr;
    unsigned int plen, vno;
    krb5_data ap_req, ap_rep = empty_data();
    krb5_data cipher = empty_data(), clear = empty_data();
    krb5_auth_context auth_context = NULL;
    krb5_principal changepw = NULL;
    krb5_principal client, target = NULL;
    krb5_ticket *ticket = NULL;
    krb5_replay_data replay;
    krb5_error krberror;
    int numresult;
    char strresult[1024];
    char *clientstr = NULL, *targetstr = NULL;
    const char *errmsg = NULL;
    size_t clen;
    char *cdots;
    struct sockaddr_storage ss;
    socklen_t salen;
    char addrbuf[100];
    krb5_address *addr = remote_faddr->address;

    *rep = empty_data();

    if (req->length < 4) {
        /* either this, or the server is printing bad messages,
           or the caller passed in garbage */
        ret = KRB5KRB_AP_ERR_MODIFIED;
        numresult = KRB5_KPASSWD_MALFORMED;
        strlcpy(strresult, "Request was truncated", sizeof(strresult));
        goto bailout;
    }

    ptr = req->data;

    /* verify length */

    plen = (*ptr++ & 0xff);
    plen = (plen<<8) | (*ptr++ & 0xff);

    if (plen != req->length) {
        ret = KRB5KRB_AP_ERR_MODIFIED;
        numresult = KRB5_KPASSWD_MALFORMED;
        strlcpy(strresult, "Request length was inconsistent",
                sizeof(strresult));
        goto bailout;
    }

    /* verify version number */

    vno = (*ptr++ & 0xff) ;
    vno = (vno<<8) | (*ptr++ & 0xff);

    if (vno != 1 && vno != RFC3244_VERSION) {
        ret = KRB5KDC_ERR_BAD_PVNO;
        numresult = KRB5_KPASSWD_BAD_VERSION;
        snprintf(strresult, sizeof(strresult),
                 "Request contained unknown protocol version number %d", vno);
        goto bailout;
    }

    /* read, check ap-req length */

    ap_req.length = (*ptr++ & 0xff);
    ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff);

    if (ptr + ap_req.length >= req->data + req->length) {
        ret = KRB5KRB_AP_ERR_MODIFIED;
        numresult = KRB5_KPASSWD_MALFORMED;
        strlcpy(strresult, "Request was truncated in AP-REQ",
                sizeof(strresult));
        goto bailout;
    }

    /* verify ap_req */

    ap_req.data = ptr;
    ptr += ap_req.length;

    ret = krb5_auth_con_init(context, &auth_context);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed initializing auth context",
                sizeof(strresult));
        goto chpwfail;
    }

    ret = krb5_auth_con_setflags(context, auth_context,
                                 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed initializing auth context",
                sizeof(strresult));
        goto chpwfail;
    }

    ret = krb5_build_principal(context, &changepw, strlen(realm), realm,
                               "kadmin", "changepw", NULL);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed building kadmin/changepw principal",
                sizeof(strresult));
        goto chpwfail;
    }

    ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab,
                      NULL, &ticket);

    if (ret) {
        numresult = KRB5_KPASSWD_AUTHERROR;
        strlcpy(strresult, "Failed reading application request",
                sizeof(strresult));
        goto chpwfail;
    }

    /* construct the ap-rep */

    ret = krb5_mk_rep(context, auth_context, &ap_rep);
    if (ret) {
        numresult = KRB5_KPASSWD_AUTHERROR;
        strlcpy(strresult, "Failed replying to application request",
                sizeof(strresult));
        goto chpwfail;
    }

    /* decrypt the ChangePasswdData */

    cipher.length = (req->data + req->length) - ptr;
    cipher.data = ptr;

    /*
     * Don't set a remote address in auth_context before calling krb5_rd_priv,
     * so that we can work against clients behind a NAT.  Reflection attacks
     * aren't a concern since we use sequence numbers and since our requests
     * don't look anything like our responses.  Also don't set a local address,
     * since we don't know what interface the request was received on.
     */

    ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay);
    if (ret) {
        numresult = KRB5_KPASSWD_HARDERROR;
        strlcpy(strresult, "Failed decrypting request", sizeof(strresult));
        goto chpwfail;
    }

    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;
        }

        zapfree(clear.data, clear.length);

        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 = k5memdup0(clear.data, clear.length, &ret);
    ret = schpw_util_wrapper(server_handle, client, target,
                             (ticket->enc_part2->flags & TKT_FLG_INITIAL) != 0,
                             ptr, NULL, strresult, sizeof(strresult));
    if (ret)
        errmsg = krb5_get_error_message(context, ret);

    /* zap the password */
    zapfree(clear.data, clear.length);
    zapfree(ptr, clear.length);
    clear = empty_data();

    clen = strlen(clientstr);
    trunc_name(&clen, &cdots);

    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));

    if (vno == RFC3244_VERSION) {
        size_t tlen;
        char *tdots;
        const char *targetp;

        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,
                         errmsg ? errmsg : "success");
    } else {
        krb5_klog_syslog(LOG_NOTICE, _("chpw request from %s for %.*s%s: %s"),
                         addrbuf, (int) clen, clientstr, cdots,
                         errmsg ? errmsg : "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_Q_GENERIC:
    case KADM5_PASS_TOOSOON:
        numresult = KRB5_KPASSWD_SOFTERROR;
        break;
    case 0:
        numresult = KRB5_KPASSWD_SUCCESS;
        strlcpy(strresult, "", sizeof(strresult));
        break;
    default:
        numresult = KRB5_KPASSWD_HARDERROR;
        break;
    }

chpwfail:

    ret = alloc_data(&clear, 2 + strlen(strresult));
    if (ret)
        goto bailout;

    ptr = clear.data;

    *ptr++ = (numresult>>8) & 0xff;
    *ptr++ = numresult & 0xff;

    memcpy(ptr, strresult, strlen(strresult));

    cipher = empty_data();

    if (ap_rep.length) {
        ret = krb5_auth_con_setaddrs(context, auth_context,
                                     local_faddr->address, NULL);
        if (ret) {
            numresult = KRB5_KPASSWD_HARDERROR;
            strlcpy(strresult,
                    "Failed storing client and server internet addresses",
                    sizeof(strresult));
        } else {
            ret = krb5_mk_priv(context, auth_context, &clear, &cipher,
                               &replay);
            if (ret) {
                numresult = KRB5_KPASSWD_HARDERROR;
                strlcpy(strresult, "Failed encrypting reply",
                        sizeof(strresult));
            }
        }
    }

    /* if no KRB-PRIV was constructed, then we need a KRB-ERROR.
       if this fails, just bail.  there's nothing else we can do. */

    if (cipher.length == 0) {
        /* clear out ap_rep now, so that it won't be inserted in the
           reply */

        if (ap_rep.length) {
            free(ap_rep.data);
            ap_rep = empty_data();
        }

        krberror.ctime = 0;
        krberror.cusec = 0;
        krberror.susec = 0;
        ret = krb5_timeofday(context, &krberror.stime);
        if (ret)
            goto bailout;

        /* this is really icky.  but it's what all the other callers
           to mk_error do. */
        krberror.error = ret;
        krberror.error -= ERROR_TABLE_BASE_krb5;
        if (krberror.error < 0 || krberror.error > KRB_ERR_MAX)
            krberror.error = KRB_ERR_GENERIC;

        krberror.client = NULL;

        ret = krb5_build_principal(context, &krberror.server,
                                   strlen(realm), realm,
                                   "kadmin", "changepw", NULL);
        if (ret)
            goto bailout;
        krberror.text.length = 0;
        krberror.e_data = clear;

        ret = krb5_mk_error(context, &krberror, &cipher);

        krb5_free_principal(context, krberror.server);

        if (ret)
            goto bailout;
    }

    /* construct the reply */

    ret = alloc_data(rep, 6 + ap_rep.length + cipher.length);
    if (ret)
        goto bailout;
    ptr = rep->data;

    /* length */

    *ptr++ = (rep->length>>8) & 0xff;
    *ptr++ = rep->length & 0xff;

    /* version == 0x0001 big-endian */

    *ptr++ = 0;
    *ptr++ = 1;

    /* ap_rep length, big-endian */

    *ptr++ = (ap_rep.length>>8) & 0xff;
    *ptr++ = ap_rep.length & 0xff;

    /* ap-rep data */

    if (ap_rep.length) {
        memcpy(ptr, ap_rep.data, ap_rep.length);
        ptr += ap_rep.length;
    }

    /* krb-priv or krb-error */

    memcpy(ptr, cipher.data, cipher.length);

bailout:
    krb5_auth_con_free(context, auth_context);
    krb5_free_principal(context, changepw);
    krb5_free_ticket(context, ticket);
    free(ap_rep.data);
    free(clear.data);
    free(cipher.data);
    krb5_free_principal(context, target);
    krb5_free_unparsed_name(context, targetstr);
    krb5_free_unparsed_name(context, clientstr);
    krb5_free_error_message(context, errmsg);
    return ret;
}
예제 #16
0
파일: chgpwd.c 프로젝트: andreiw/polaris
static krb5_error_code
process_chpw_request(krb5_context context, void *server_handle,
			char *realm, int s, krb5_keytab keytab,
			struct sockaddr_in *sin, 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_ticket *ticket;
	krb5_data cipher, clear;
	struct sockaddr local_addr, remote_addr;
	int addrlen;
	krb5_replay_data replay;
	krb5_error krberror;
	int numresult;
	char strresult[1024];

	ret = 0;
	rep->length = 0;

	auth_context = NULL;
	changepw = NULL;
	ap_rep.length = 0;
	ap_rep.data = NULL;
	ticket = NULL;
	clear.length = 0;
	clear.data = NULL;
	cipher.length = 0;
	cipher.data = NULL;

	if (req->length < 4) {
		/*
		 * either this, or the server is printing bad messages,
		 * or the caller passed in garbage
		 */
		ret = KRB5KRB_AP_ERR_MODIFIED;
		numresult = KRB5_KPASSWD_MALFORMED;
		(void) strlcpy(strresult, "Request was truncated",
				sizeof (strresult));
		goto chpwfail;
	}

	ptr = req->data;

	/*
	 * Verify length
	 */
	plen = (*ptr++ & 0xff);
	plen = (plen<<8) | (*ptr++ & 0xff);

	if (plen != req->length)
		return (KRB5KRB_AP_ERR_MODIFIED);

	/*
	 * Verify version number
	 */
	vno = (*ptr++ & 0xff);
	vno = (vno<<8) | (*ptr++ & 0xff);

	if (vno != 1) {
		ret = KRB5KDC_ERR_BAD_PVNO;
		numresult = KRB5_KPASSWD_MALFORMED;
		(void) snprintf(strresult, sizeof (strresult),
		    "Request contained unknown protocol version number %d",
		    vno);
		goto chpwfail;
	}

	/*
	 * Read, check ap-req length
	 */
	ap_req.length = (*ptr++ & 0xff);
	ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff);

	if (ptr + ap_req.length >= req->data + req->length) {
		ret = KRB5KRB_AP_ERR_MODIFIED;
		numresult = KRB5_KPASSWD_MALFORMED;
		(void) strlcpy(strresult, "Request was truncated in AP-REQ",
					sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Verify ap_req
	 */
	ap_req.data = ptr;
	ptr += ap_req.length;

	if (ret = krb5_auth_con_init(context, &auth_context)) {
		krb5_klog_syslog(LOG_ERR,
				gettext("Change password request failed. "
					"Failed initializing auth context: %s"),
				error_message(ret));
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Failed initializing auth context",
					sizeof (strresult));
		goto chpwfail;
	}

	if (ret = krb5_auth_con_setflags(context, auth_context,
					KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
		krb5_klog_syslog(LOG_ERR,
				gettext("Change password request failed. "
						"Failed setting auth "
					    "context flags: %s"),
				error_message(ret));
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Failed initializing auth context",
					sizeof (strresult));
		goto chpwfail;
	}

	if (ret = krb5_build_principal(context, &changepw, strlen(realm), realm,
				    "kadmin", "changepw", NULL)) {
		krb5_klog_syslog(LOG_ERR,
			gettext("Change password request failed "
					"Failed to build kadmin/changepw "
					"principal: %s"),
			error_message(ret));
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult,
				"Failed building kadmin/changepw principal",
				sizeof (strresult));
		goto chpwfail;
	}

	ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab,
			NULL, &ticket);

	if (ret) {
		char kt_name[MAX_KEYTAB_NAME_LEN];
		if (krb5_kt_get_name(context, keytab,
				kt_name, sizeof (kt_name)))
			strncpy(kt_name, "default keytab", sizeof (kt_name));

		switch (ret) {
		case KRB5_KT_NOTFOUND:
		krb5_klog_syslog(LOG_ERR,
			gettext("Change password request failed because "
					"keytab entry \"kadmin/changepw\" "
					"is missing from \"%s\""),
			kt_name);
		break;
		case ENOENT:
		krb5_klog_syslog(LOG_ERR,
			gettext("Change password request failed because "
					"keytab file \"%s\" does not exist"),
			kt_name);
		break;
		default:
		krb5_klog_syslog(LOG_ERR,
			gettext("Change password request failed. "
				"Failed to parse Kerberos AP_REQ message: %s"),
			error_message(ret));
		}

		numresult = KRB5_KPASSWD_AUTHERROR;
		(void) strlcpy(strresult, "Failed reading application request",
					sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Set up address info
	 */
	addrlen = sizeof (local_addr);

	if (getsockname(s, &local_addr, &addrlen) < 0) {
		ret = errno;
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) 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);
		/* CSTYLED */
		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;
		if ((local_kaddr.contents = malloc(addrs[0]->length)) == 0) {
			ret = errno;
			numresult = KRB5_KPASSWD_HARDERROR;
			(void) strlcpy(strresult,
				"Malloc failed for local_kaddr",
				sizeof (strresult));
			goto chpwfail;
		}

		(void) 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;
		(void) 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);
	/* CSTYLED */
	remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *)&remote_addr)->sin_addr);
	remote_kaddr.addrtype = ADDRTYPE_INET;
	remote_kaddr.length = sizeof (sin->sin_addr);
	remote_kaddr.contents = (krb5_octet *) &sin->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 (ret = krb5_auth_con_setaddrs(context, auth_context, NULL,
					&remote_kaddr)) {
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult,
				"Failed storing client internet address",
				sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Verify that this is an AS_REQ ticket
	 */
	if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) {
		numresult = KRB5_KPASSWD_AUTHERROR;
		(void) strlcpy(strresult,
				"Ticket must be derived from a password",
				sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Construct the ap-rep
	 */
	if (ret = krb5_mk_rep(context, auth_context, &ap_rep)) {
		numresult = KRB5_KPASSWD_AUTHERROR;
		(void) strlcpy(strresult,
				"Failed replying to application request",
				sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Decrypt the new password
	 */
	cipher.length = (req->data + req->length) - ptr;
	cipher.data = ptr;

	if (ret = krb5_rd_priv(context, auth_context, &cipher,
				&clear, &replay)) {
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Failed decrypting request",
					sizeof (strresult));
		goto chpwfail;
	}

	/*
	 * Change the password
	 */
	if ((ptr = (char *)malloc(clear.length + 1)) == NULL) {
		ret = errno;
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Malloc failed for ptr",
			sizeof (strresult));
		goto chpwfail;
	}
	(void) memcpy(ptr, clear.data, clear.length);
	ptr[clear.length] = '\0';

	ret = (kadm5_ret_t)kadm5_chpass_principal_util(server_handle,
						ticket->enc_part2->client,
						ptr, NULL, strresult,
						sizeof (strresult));
	/*
	 * Zap the password
	 */
	(void) memset(clear.data, 0, clear.length);
	(void) memset(ptr, 0, clear.length);
	if (clear.data != NULL) {
		krb5_xfree(clear.data);
		clear.data = NULL;
	}
	free(ptr);
	clear.length = 0;

	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;
	}

	/*
	 * Success!
	 */
	numresult = KRB5_KPASSWD_SUCCESS;
	(void) strlcpy(strresult, "", sizeof (strresult));

chpwfail:

	clear.length = 2 + strlen(strresult);
	if (clear.data != NULL) {
		krb5_xfree(clear.data);
		clear.data = NULL;
	}
	if ((clear.data = (char *)malloc(clear.length)) == NULL) {
		ret = errno;
		numresult = KRB5_KPASSWD_HARDERROR;
		(void) strlcpy(strresult, "Malloc failed for clear.data",
			sizeof (strresult));
	}

	cipher.length = 0;

	if (ap_rep.length) {
		if (ret = krb5_auth_con_setaddrs(context, auth_context,
					&local_kaddr, NULL)) {
		    numresult = KRB5_KPASSWD_HARDERROR;
		    (void) strlcpy(strresult,
			"Failed storing client and server internet addresses",
			sizeof (strresult));
		} else {
			if (ret = krb5_mk_priv(context, auth_context, &clear,
						&cipher, &replay)) {
				numresult = KRB5_KPASSWD_HARDERROR;
				(void) strlcpy(strresult,
					"Failed encrypting reply",
					sizeof (strresult));
			}
		}
	}

	ptr = clear.data;
	*ptr++ = (numresult>>8) & 0xff;
	*ptr++ = numresult & 0xff;

	(void) memcpy(ptr, strresult, strlen(strresult));

	/*
	 * If no KRB-PRIV was constructed, then we need a KRB-ERROR.
	 * If this fails, just bail.  There's nothing else we can do.
	 */
	if (cipher.length == 0) {
		/*
		 * Clear out ap_rep now, so that it won't be inserted
		 * in the reply
		 */
		if (ap_rep.length) {
			if (ap_rep.data != NULL)
				krb5_xfree(ap_rep.data);
			ap_rep.data = NULL;
			ap_rep.length = 0;
		}

		krberror.ctime = 0;
		krberror.cusec = 0;
		krberror.susec = 0;
		if (ret = krb5_timeofday(context, &krberror.stime))
			goto bailout;

		/*
		 * This is really icky.  but it's what all the other callers
		 * to mk_error do.
		 */
		krberror.error = ret;
		krberror.error -= ERROR_TABLE_BASE_krb5;
		if (krberror.error < 0 || krberror.error > 128)
			krberror.error = KRB_ERR_GENERIC;

		krberror.client = NULL;
		if (ret = krb5_build_principal(context, &krberror.server,
					    strlen(realm), realm,
					    "kadmin", "changepw", NULL)) {
			goto bailout;
		}

		krberror.text.length = 0;
		krberror.e_data = clear;

		ret = krb5_mk_error(context, &krberror, &cipher);

		krb5_free_principal(context, krberror.server);

		if (ret)
			goto bailout;
	}

	/*
	 * Construct the reply
	 */
	rep->length = 6 + ap_rep.length + cipher.length;
	if ((rep->data = (char *)malloc(rep->length)) == NULL)  {
		ret = errno;
		goto bailout;
	}
	ptr = rep->data;

	/*
	 * Length
	 */
	*ptr++ = (rep->length>>8) & 0xff;
	*ptr++ = rep->length & 0xff;

	/*
	 * Version == 0x0001 big-endian
	 */
	*ptr++ = 0;
	*ptr++ = 1;

	/*
	 * ap_rep length, big-endian
	 */
	*ptr++ = (ap_rep.length>>8) & 0xff;
	*ptr++ = ap_rep.length & 0xff;

	/*
	 * ap-rep data
	 */
	if (ap_rep.length) {
		(void) memcpy(ptr, ap_rep.data, ap_rep.length);
		ptr += ap_rep.length;
	}

	/*
	 * krb-priv or krb-error
	 */
	(void) memcpy(ptr, cipher.data, cipher.length);

bailout:
	if (auth_context)
		krb5_auth_con_free(context, auth_context);
	if (changepw)
		krb5_free_principal(context, changepw);
	if (ap_rep.data != NULL)
		krb5_xfree(ap_rep.data);
	if (ticket)
		krb5_free_ticket(context, ticket);
	if (clear.data != NULL)
		krb5_xfree(clear.data);
	if (cipher.data != NULL)
		krb5_xfree(cipher.data);
	if (allocated_mem)
		krb5_xfree(local_kaddr.contents);

	return (ret);
}