| /* |
| * Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved. |
| * |
| * Licensed under the Apache License 2.0 (the "License"). You may not use |
| * this file except in compliance with the License. You can obtain a copy |
| * in the file LICENSE in the source distribution or at |
| * https://www.openssl.org/source/license.html |
| */ |
| |
| #include <openssl/opensslconf.h> |
| |
| #include <openssl/crypto.h> |
| #include <openssl/e_os2.h> |
| #include <openssl/rand.h> |
| |
| /* |
| * Query an EGD |
| */ |
| |
| #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_VOS) || defined(OPENSSL_SYS_UEFI) |
| int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes) |
| { |
| return -1; |
| } |
| |
| int RAND_egd(const char *path) |
| { |
| return -1; |
| } |
| |
| int RAND_egd_bytes(const char *path, int bytes) |
| { |
| return -1; |
| } |
| |
| #else |
| |
| # include <unistd.h> |
| # include <stddef.h> |
| # include <sys/types.h> |
| # include <sys/socket.h> |
| # ifndef NO_SYS_UN_H |
| # ifdef OPENSSL_SYS_VXWORKS |
| # include <streams/un.h> |
| # else |
| # include <sys/un.h> |
| # endif |
| # else |
| struct sockaddr_un { |
| short sun_family; /* AF_UNIX */ |
| char sun_path[108]; /* path name (gag) */ |
| }; |
| # endif /* NO_SYS_UN_H */ |
| # include <string.h> |
| # include <errno.h> |
| |
| # if defined(OPENSSL_SYS_TANDEM) |
| /* |
| * HPNS: |
| * |
| * Our current MQ 5.3 EGD requires compatability-mode sockets |
| * This code forces the mode to compatibility if required |
| * and then restores the mode. |
| * |
| * Needs review: |
| * |
| * The better long-term solution is to either run two EGD's each in one of |
| * the two modes or revise the EGD code to listen on two different sockets |
| * (each in one of the two modes). |
| */ |
| _variable |
| int hpns_socket(int family, |
| int type, |
| int protocol, |
| char* transport) |
| { |
| int socket_rc; |
| char current_transport[20]; |
| |
| # define AF_UNIX_PORTABILITY "$ZAFN2" |
| # define AF_UNIX_COMPATIBILITY "$ZPLS" |
| |
| if (!_arg_present(transport) || transport == NULL || transport[0] == '\0') |
| return socket(family, type, protocol); |
| |
| socket_transport_name_get(AF_UNIX, current_transport, 20); |
| |
| if (strcmp(current_transport, transport) == 0) |
| return socket(family, type, protocol); |
| |
| /* set the requested socket transport */ |
| if (socket_transport_name_set(AF_UNIX, transport)) |
| return -1; |
| |
| socket_rc = socket(family, type, protocol); |
| |
| /* set mode back to what it was */ |
| if (socket_transport_name_set(AF_UNIX, current_transport)) |
| return -1; |
| |
| return socket_rc; |
| } |
| |
| /*#define socket(a,b,c,...) hpns_socket(a,b,c,__VA_ARGS__) */ |
| |
| static int hpns_connect_attempt = 0; |
| |
| # endif /* defined(OPENSSL_SYS_HPNS) */ |
| |
| |
| int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes) |
| { |
| FILE *fp = NULL; |
| struct sockaddr_un addr; |
| int mybuffer, ret = -1, i, numbytes, fd; |
| unsigned char tempbuf[255]; |
| |
| if (bytes > (int)sizeof(tempbuf)) |
| return -1; |
| |
| /* Make socket. */ |
| memset(&addr, 0, sizeof(addr)); |
| addr.sun_family = AF_UNIX; |
| if (strlen(path) >= sizeof(addr.sun_path)) |
| return -1; |
| strcpy(addr.sun_path, path); |
| i = offsetof(struct sockaddr_un, sun_path) + strlen(path); |
| #if defined(OPENSSL_SYS_TANDEM) |
| fd = hpns_socket(AF_UNIX, SOCK_STREAM, 0, AF_UNIX_COMPATIBILITY); |
| #else |
| fd = socket(AF_UNIX, SOCK_STREAM, 0); |
| #endif |
| if (fd == -1 || (fp = fdopen(fd, "r+")) == NULL) |
| return -1; |
| setbuf(fp, NULL); |
| |
| /* Try to connect */ |
| for (;;) { |
| if (connect(fd, (struct sockaddr *)&addr, i) == 0) |
| break; |
| # ifdef EISCONN |
| if (errno == EISCONN) |
| break; |
| # endif |
| switch (errno) { |
| # ifdef EINTR |
| case EINTR: |
| # endif |
| # ifdef EAGAIN |
| case EAGAIN: |
| # endif |
| # ifdef EINPROGRESS |
| case EINPROGRESS: |
| # endif |
| # ifdef EALREADY |
| case EALREADY: |
| # endif |
| /* No error, try again */ |
| break; |
| default: |
| # if defined(OPENSSL_SYS_TANDEM) |
| if (hpns_connect_attempt == 0) { |
| /* try the other kind of AF_UNIX socket */ |
| close(fd); |
| fd = hpns_socket(AF_UNIX, SOCK_STREAM, 0, AF_UNIX_PORTABILITY); |
| if (fd == -1) |
| return -1; |
| ++hpns_connect_attempt; |
| break; /* try the connect again */ |
| } |
| # endif |
| |
| ret = -1; |
| goto err; |
| } |
| } |
| |
| /* Make request, see how many bytes we can get back. */ |
| tempbuf[0] = 1; |
| tempbuf[1] = bytes; |
| if (fwrite(tempbuf, sizeof(char), 2, fp) != 2 || fflush(fp) == EOF) |
| goto err; |
| if (fread(tempbuf, sizeof(char), 1, fp) != 1 || tempbuf[0] == 0) |
| goto err; |
| numbytes = tempbuf[0]; |
| |
| /* Which buffer are we using? */ |
| mybuffer = buf == NULL; |
| if (mybuffer) |
| buf = tempbuf; |
| |
| /* Read bytes. */ |
| i = fread(buf, sizeof(char), numbytes, fp); |
| if (i < numbytes) |
| goto err; |
| ret = numbytes; |
| if (mybuffer) |
| RAND_add(tempbuf, i, i); |
| |
| err: |
| if (fp != NULL) |
| fclose(fp); |
| return ret; |
| } |
| |
| int RAND_egd_bytes(const char *path, int bytes) |
| { |
| int num; |
| |
| num = RAND_query_egd_bytes(path, NULL, bytes); |
| if (num < 0) |
| return -1; |
| if (RAND_status() != 1) |
| return -1; |
| return num; |
| } |
| |
| int RAND_egd(const char *path) |
| { |
| return RAND_egd_bytes(path, 255); |
| } |
| |
| #endif |