int load_config( char **ip, int *t_port, int *d_port) { int rc = PBSE_NONE; char *tmp_name = pbs_default(); /* Assume TORQUE_HOME = /var/spool/torque */ /* /var/spool/torque/server_name */ if (tmp_name == NULL) rc = PBSE_BADHOST; else { /* Currently this only display's the port for the trq server * from the lib_ifl.h file or server_name file (The same way * the client utilities determine the pbs_server port) */ printf("hostname: %s\n", tmp_name); *ip = tmp_name; PBS_get_server(tmp_name, (unsigned int *)t_port); if (*t_port == 0) *t_port = PBS_BATCH_SERVICE_PORT; *d_port = TRQ_AUTHD_SERVICE_PORT; } return rc; }
void get_port_from_server_name_file(unsigned int *server_name_file_port) { char *the_server = pbs_default(); if (the_server != NULL) { PBS_get_server(the_server, server_name_file_port); } }
/* Get the name of the active pbs_server */ int load_trqauthd_config( char **default_server_name, int *t_port, char **trqauthd_unix_domain_port) { int rc = PBSE_NONE; char *tmp_name = NULL; int unix_domain_len; tmp_name = pbs_default(); if ((tmp_name == NULL) || (tmp_name[0] == '\0')) rc = PBSE_BADHOST; else { /* Currently this only display's the port for the trq server * from the lib_ifl.h file or server_name file (The same way * the client utilities determine the pbs_server port) */ printf("hostname: %s\n", tmp_name); *default_server_name = tmp_name; PBS_get_server(tmp_name, (unsigned int *)t_port); if (*t_port == 0) *t_port = PBS_BATCH_SERVICE_PORT; unix_domain_len = strlen(TRQAUTHD_SOCK_DIR); unix_domain_len += strlen(TRQAUTHD_SOCK_NAME) + 2; /* on for the "/" and one for zero termination*/ *trqauthd_unix_domain_port = (char *)malloc(unix_domain_len); if (*trqauthd_unix_domain_port == NULL) { fprintf(stderr, "could not allocate memory for unix domain port"); return(PBSE_MEM_MALLOC); } strcpy(*trqauthd_unix_domain_port, TRQAUTHD_SOCK_DIR); strcat(*trqauthd_unix_domain_port, "/"); strcat(*trqauthd_unix_domain_port, TRQAUTHD_SOCK_NAME); set_active_pbs_server(tmp_name, *t_port); } return rc; }
int pbs_original_connect( char *server) /* I (FORMAT: NULL | '\0' | HOSTNAME | HOSTNAME:PORT )*/ { struct sockaddr_in server_addr; char *if_name; struct addrinfo *addr_info; int out; int i; int opt_value = 1; int rc = PBSE_NONE; int local_errno; struct sockaddr preferred_addr; /* set if TRQ_IFNAME set in torque.cfg */ struct passwd *pw; int use_unixsock = 0; uid_t pbs_current_uid; long sockflags; int retry = 1; #ifdef ENABLE_UNIX_SOCKETS struct sockaddr_un unserver_addr; char hnamebuf[256]; #endif char *ptr; memset(&server_addr, 0, sizeof(server_addr)); /* Read the timeout from the environment */ if ((ptr = getenv("PBSAPITIMEOUT")) != NULL) { pbs_tcp_timeout = strtol(ptr, NULL, 0); if (pbs_tcp_timeout <= 0) pbs_tcp_timeout = 300; if (pbs_tcp_timeout > 2) retry = 0; } else pbs_tcp_timeout = 300; /* reserve a connection state record */ out = -1; for (i = 1;i < NCONNECTS;i++) { if (connection[i].ch_mutex == NULL) { connection[i].ch_mutex = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t)); pthread_mutex_init(connection[i].ch_mutex,NULL); } pthread_mutex_lock(connection[i].ch_mutex); if (connection[i].ch_inuse == FALSE) { out = i; connection[out].ch_inuse = TRUE; connection[out].ch_errno = 0; connection[out].ch_socket = -1; connection[out].ch_errtxt = NULL; break; } pthread_mutex_unlock(connection[i].ch_mutex); } if (out < 0) { if (getenv("PBSDEBUG")) fprintf(stderr, "ALERT: cannot locate free channel\n"); /* FAILURE */ /* no need to unlock mutex here - in this case no connection was found */ return(PBSE_NOCONNECTS * -1); } /* get server host and port */ server = PBS_get_server(server, &server_port); if (server == NULL) { connection[out].ch_inuse = FALSE; pthread_mutex_unlock(connection[out].ch_mutex); if (getenv("PBSDEBUG")) fprintf(stderr, "ALERT: PBS_get_server() failed\n"); rc = PBSE_NOSERVER * -1; goto cleanup_conn_lite; } /* determine who we are */ pbs_current_uid = getuid(); if ((pw = getpwuid(pbs_current_uid)) == NULL) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ALERT: cannot get password info for uid %ld\n", (long)pbs_current_uid); } rc = PBSE_NOSERVER * -1; goto cleanup_conn_lite; } snprintf(pbs_current_user, PBS_MAXUSER, "%s", pw->pw_name); pbs_server = server; /* set for error messages from commands */ #ifdef ENABLE_UNIX_SOCKETS /* determine if we want to use unix domain socket */ if (!strcmp(server, "localhost")) use_unixsock = 1; else if ((gethostname(hnamebuf, sizeof(hnamebuf) - 1) == 0) && !strcmp(hnamebuf, server)) use_unixsock = 1; /* NOTE: if any part of using unix domain sockets fails, * we just cleanup and try again with inet sockets */ /* get socket */ if (use_unixsock) { connection[out].ch_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (connection[out].ch_socket < 0) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot create socket: errno=%d (%s)\n", errno, strerror(errno)); } connection[out].ch_inuse = FALSE; local_errno = PBSE_PROTOCOL; use_unixsock = 0; } } /* and connect... */ if (use_unixsock) { unserver_addr.sun_family = AF_UNIX; strcpy(unserver_addr.sun_path, TSOCK_PATH); if (connect( connection[out].ch_socket, (struct sockaddr *)&unserver_addr, (strlen(unserver_addr.sun_path) + sizeof(unserver_addr.sun_family))) < 0) { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; local_errno = errno; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot connect to server, errno=%d (%s)\n", errno, strerror(errno)); } use_unixsock = 0; /* will try again with inet socket */ } } if (use_unixsock) { if (!send_unix_creds(connection[out].ch_socket)) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot send unix creds to pbs_server: errno=%d (%s)\n", errno, strerror(errno)); } close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; local_errno = PBSE_PROTOCOL; use_unixsock = 0; /* will try again with inet socket */ } } #endif /* END ENABLE_UNIX_SOCKETS */ if (!use_unixsock) { int retries = 0; std::string err_msg; /* at this point, either using unix sockets failed, or we determined not to * try */ do { connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); if (connection[out].ch_socket < 0) { if (getenv("PBSDEBUG")) { if (!retry || retries >= MAX_RETRIES) fprintf(stderr, "ERROR: cannot connect to server \"%s\", errno=%d (%s)\n", server, errno, strerror(errno)); } retries++; if (!retry || retries >= MAX_RETRIES) { rc = PBSE_SYSTEM * -1; goto cleanup_conn; } else { connection[out].ch_inuse = FALSE; pthread_mutex_unlock(connection[out].ch_mutex); usleep(1000); continue; } } if (setsockopt(connection[out].ch_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof(opt_value))) perror("Couldn't set socket option"); /* This is probably an IPv4 solution for the if_name and preferred_addr We need to see what ioctl call we need for IPv6 */ if_name = trq_get_if_name(); if (if_name) { rc = trq_set_preferred_network_interface(if_name, &preferred_addr); if (rc != PBSE_NONE) { if (!retry || retries >= MAX_RETRIES) fprintf(stderr, "could not set preferred network interface (%s): %d\n", if_name, rc); if (if_name) free(if_name); retries++; if (!retry || retries >= MAX_RETRIES) { rc = rc * -1; goto cleanup_conn; } else { connection[out].ch_inuse = FALSE; pthread_mutex_unlock(connection[out].ch_mutex); usleep(1000); continue; } } rc = bind(connection[out].ch_socket, &preferred_addr, sizeof(struct sockaddr)); if (rc < 0) { if (!retry || retries >= MAX_RETRIES) fprintf(stderr, "ERROR: could not bind preferred network interface (%s): errno: %d", if_name, errno); if (if_name) free(if_name); retries++; if (!retry || retries >= MAX_RETRIES) { rc = PBSE_SYSTEM * -1; goto cleanup_conn; } else { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; usleep(1000); continue; } } } /* we are done with if_name at this point. trq_get_if_name allocated space for it. We need to free it */ if (if_name) free(if_name); server_addr.sin_family = AF_INET; if ((rc = pbs_getaddrinfo(server, NULL, &addr_info)) != 0) { if (getenv("PBSDEBUG")) { if (!retry || retries >= MAX_RETRIES) fprintf(stderr, "ERROR: cannot get servername (%s) errno=%d (%s)\n", server, errno, strerror(errno)); } retries++; if (!retry || retries >= MAX_RETRIES) { rc = PBSE_BADHOST * -1; goto cleanup_conn; } else { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; usleep(1000); continue; } } server_addr.sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr; server_addr.sin_port = htons(server_port); /* Set the socket to non-blocking mode so we can timeout */ if ((sockflags = fcntl(connection[out].ch_socket, F_GETFL, NULL)) < 0) { retries++; if (!retry || retries >= MAX_RETRIES) { if (getenv("PBSDEBUG")) fprintf(stderr, "ERROR: getting socket flags failed\n"); rc = errno * -1; goto cleanup_conn; } else { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; rc = sockflags; usleep(1000); continue; } } sockflags |= O_NONBLOCK; if ((rc = fcntl(connection[out].ch_socket, F_SETFL, sockflags)) < 0) { retries++; if (!retry || retries >= MAX_RETRIES) { if (getenv("PBSDEBUG")) fprintf(stderr, "ERROR: setting socket flags failed\n"); rc = errno * -1; goto cleanup_conn; } else { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; usleep(1000); continue; } } int sock = connection[out].ch_socket; int conn_retries = 0; while (((rc = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) != 0) && (conn_retries < MAX_RETRIES)) { rc = socket_wait_for_write(sock); if (rc == PERMANENT_SOCKET_FAIL) { rc = errno; break; } conn_retries++; } if (rc != 0) { close(sock); retries++; continue; } // if we are at this point, connect has succeeded, proceed to authorize /* Set the socket back to blocking so read()s actually work */ sockflags &= (~O_NONBLOCK); if ((rc = fcntl(connection[out].ch_socket, F_SETFL, sockflags)) < 0) { if (getenv("PBSDEBUG")) fprintf(stderr, "ERROR: setting socket flags failed\n"); retries++; if (!retry || retries >= MAX_RETRIES) { rc = PBSE_SOCKET_FAULT * -1; goto cleanup_conn; } else { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; usleep(1000); continue; } } /* FIXME: is this necessary? Contributed by one user that fixes a problem, but doesn't fix the same problem for another user! */ #if 0 #if defined(__hpux) /*HP-UX : avoiding socket caching */ send(connection[out].ch_socket, '?', 1, MSG_OOB); #endif #endif #ifdef MUNGE_AUTH rc = PBSD_munge_authenticate(connection[out].ch_socket, out); if (rc != 0) { if (rc == PBSE_MUNGE_NOT_FOUND) { local_errno = PBSE_MUNGE_NOT_FOUND; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot find munge executable\n"); } rc = -1 * local_errno; goto cleanup_conn; } else { retries++; if (!retry || retries >= MAX_RETRIES) { local_errno = PBSE_PERM; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot authenticate connection to server \"%s\", errno=%d (%s)\n", server, errno, strerror(errno)); } rc = -1 * local_errno; goto cleanup_conn; } else { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; usleep(1000); continue; } } } #else /* new version of iff using daemon */ if ((ENABLE_TRUSTED_AUTH == FALSE) && ((rc = validate_socket(connection[out].ch_socket, err_msg)) != PBSE_NONE)) { if (!retry || retries >= MAX_RETRIES) { if (getenv("PBSDEBUG")) { const char *tmp_err_msg = ""; if (rc > 0) tmp_err_msg = pbs_strerror(rc); fprintf(stderr, "ERROR: cannot authenticate connection to server \"%s\", errno=%d (%s)\n", server, rc, tmp_err_msg); } local_errno = PBSE_SOCKET_FAULT; rc = -1 * local_errno; goto cleanup_conn; } else { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; retries++; usleep(1000); continue; } } #endif /* ifdef MUNGE_AUTH */ } while ((rc != PBSE_NONE) && (retries < MAX_RETRIES)); if (rc != PBSE_NONE) { fprintf(stderr, "%s\n", err_msg.c_str()); goto cleanup_conn; } } /* END if !use_unixsock */ pthread_mutex_unlock(connection[out].ch_mutex); return(out); cleanup_conn: if (connection[out].ch_socket >= 0) close(connection[out].ch_socket); cleanup_conn_lite: connection[out].ch_inuse = FALSE; pthread_mutex_unlock(connection[out].ch_mutex); return(rc < 0 ? rc : rc * -1); } /* END pbs_original_connect() */
int pbs_original_connect( char *server) /* I (FORMAT: NULL | '\0' | HOSTNAME | HOSTNAME:PORT )*/ { struct sockaddr_in server_addr; struct hostent *hp; int out; int i; #ifdef GSSAPI int neediff = 0; #endif int auth; struct passwd *pw; int use_unixsock = 0; #ifdef ENABLE_UNIX_SOCKETS struct sockaddr_un unserver_addr; char hnamebuf[256]; #endif char *ptr; /* reserve a connection state record */ out = -1; for (i = 1;i < NCONNECTS;i++) { if (connection[i].ch_inuse) continue; out = i; connection[out].ch_inuse = 1; connection[out].ch_errno = 0; connection[out].ch_socket = -1; connection[out].ch_errtxt = NULL; break; } if (out < 0) { pbs_errno = PBSE_NOCONNECTS; if (getenv("PBSDEBUG")) fprintf(stderr, "ALERT: cannot locate free channel\n"); /* FAILURE */ return(-1); } /* get server host and port */ server = PBS_get_server(server, &server_port); if (server == NULL) { connection[out].ch_inuse = 0; pbs_errno = PBSE_NOSERVER; if (getenv("PBSDEBUG")) fprintf(stderr, "ALERT: PBS_get_server() failed\n"); return(-1); } /* determine who we are */ pbs_current_uid = getuid(); if ((pw = getpwuid(pbs_current_uid)) == NULL) { pbs_errno = PBSE_SYSTEM; if (getenv("PBSDEBUG")) { fprintf(stderr, "ALERT: cannot get password info for uid %ld\n", (long)pbs_current_uid); } return(-1); } strcpy(pbs_current_user, pw->pw_name); pbs_server = server; /* set for error messages from commands */ #ifdef ENABLE_UNIX_SOCKETS /* determine if we want to use unix domain socket */ if (!strcmp(server, "localhost")) use_unixsock = 1; else if ((gethostname(hnamebuf, sizeof(hnamebuf) - 1) == 0) && !strcmp(hnamebuf, server)) use_unixsock = 1; /* NOTE: if any part of using unix domain sockets fails, * we just cleanup and try again with inet sockets */ /* get socket */ if (use_unixsock) { connection[out].ch_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (connection[out].ch_socket < 0) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot create socket: errno=%d (%s)\n", errno, strerror(errno)); } connection[out].ch_inuse = 0; pbs_errno = PBSE_PROTOCOL; use_unixsock = 0; } } /* and connect... */ if (use_unixsock) { unserver_addr.sun_family = AF_UNIX; strcpy(unserver_addr.sun_path, TSOCK_PATH); if (connect( connection[out].ch_socket, (struct sockaddr *)&unserver_addr, (strlen(unserver_addr.sun_path) + sizeof(unserver_addr.sun_family))) < 0) { close(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = errno; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot connect to server, errno=%d (%s)\n", errno, strerror(errno)); } use_unixsock = 0; /* will try again with inet socket */ } } if (use_unixsock) { if (!send_unix_creds(connection[out].ch_socket)) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot send unix creds to pbs_server: errno=%d (%s)\n", errno, strerror(errno)); } close(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = PBSE_PROTOCOL; use_unixsock = 0; /* will try again with inet socket */ } } #endif /* END ENABLE_UNIX_SOCKETS */ if (!use_unixsock) { /* at this point, either using unix sockets failed, or we determined not to * try */ connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); if (connection[out].ch_socket < 0) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot connect to server \"%s\", errno=%d (%s)\n", server, errno, strerror(errno)); } connection[out].ch_inuse = 0; pbs_errno = PBSE_PROTOCOL; return(-1); } /* connection succeeded re-mark as used */ connection[out].ch_inuse = 1; server_addr.sin_family = AF_INET; hp = NULL; hp = gethostbyname(server); /* setup DIS support routines for following pbs_* calls */ if (hp == NULL) { close(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = PBSE_BADHOST; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot get servername (%s) errno=%d (%s)\n", (server != NULL) ? server : "NULL", errno, strerror(errno)); } return(-1); } memcpy((char *)&server_addr.sin_addr, hp->h_addr_list[0], hp->h_length); server_addr.sin_port = htons(server_port); if (connect( connection[out].ch_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { close(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = errno; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot connect to server, errno=%d (%s)\n", errno, strerror(errno)); } return(-1); } DIS_tcp_setup(connection[out].ch_socket); if ((ptr = getenv("PBSAPITIMEOUT")) != NULL) { pbs_tcp_timeout = strtol(ptr,NULL,0); if (pbs_tcp_timeout <= 0) { pbs_tcp_timeout = 10800; /* set for 3 hour time out */ } } else { pbs_tcp_timeout = 10800; /* set for 3 hour time out */ } /* If we have GSSAPI, then try gssapi authentication first. If that fails, fall back to iff. If there's no GSSAPI, then just use iff. */ #ifdef GSSAPI if (!getenv("TORQUE_IGNORE_KERBEROS") && !ignore_kerberos_for_connection && pbsgss_can_get_creds()) { if (encode_DIS_ReqHdr(connection[out].ch_socket, PBS_BATCH_GSSAuthenUser, pbs_current_user) || encode_DIS_ReqExtend(connection[out].ch_socket,0)) { if (getenv("PBSDEBUG")) { fprintf(stderr,"ERROR: cannot authenticate connection with gssapi, errno=%d (%s)\n", errno, strerror(errno)); } neediff = 1; } else { DIS_tcp_wflush(connection[out].ch_socket); if (pbsgss_client_authenticate(server,connection[out].ch_socket,1,1) != 0) { neediff = 1; if (getenv("PBSDEBUG")) { fprintf(stderr,"ERROR: cannot authenticate connection, errno=%d (%s)\n", errno, strerror(errno)); } } } } else { neediff = 1; } if (neediff) { #endif /* FIXME: is this necessary? Contributed by one user that fixes a problem, but doesn't fix the same problem for another user! */ #if 0 #if defined(__hpux) /*HP-UX : avoiding socket caching */ send(connection[out].ch_socket, '?', 1, MSG_OOB); #endif #endif /* Have pbs_iff authenticate connection */ if ((ENABLE_TRUSTED_AUTH == FALSE) && ((auth = PBSD_authenticate(connection[out].ch_socket)) != 0)) { close(connection[out].ch_socket); connection[out].ch_inuse = 0; if (auth == ENOENT) { pbs_errno = ENOENT; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot find pbs_iif executable\n"); } } else { pbs_errno = PBSE_PERM; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot authenticate connection to server \"%s\", errno=%d (%s)\n", server, errno, strerror(errno)); } } return(-1); } #ifdef GSSAPI } /* END if neediff */ #endif } /* END !useunix */ DIS_tcp_setup(connection[out].ch_socket); if ((ptr = getenv("PBSAPITIMEOUT")) != NULL) { pbs_tcp_timeout = strtol(ptr, NULL, 0); if (pbs_tcp_timeout <= 0) { pbs_tcp_timeout = 10800; /* set for 3 hour time out */ } } else { pbs_tcp_timeout = 10800; /* set for 3 hour time out */ } return(out); } /* END pbs_original_connect() */
int pbs_original_connect( char *server) /* I (FORMAT: NULL | '\0' | HOSTNAME | HOSTNAME:PORT )*/ { struct sockaddr_in server_addr; char *if_name; struct addrinfo *addr_info; int out; int i; int rc; int local_errno; struct sockaddr preferred_addr; /* set if TRQ_IFNAME set in torque.cfg */ struct passwd *pw; int use_unixsock = 0; uid_t pbs_current_uid; #ifdef ENABLE_UNIX_SOCKETS struct sockaddr_un unserver_addr; char hnamebuf[256]; #endif char *ptr; /* reserve a connection state record */ out = -1; for (i = 1;i < NCONNECTS;i++) { if (connection[i].ch_mutex == NULL) { connection[i].ch_mutex = calloc(1, sizeof(pthread_mutex_t)); pthread_mutex_init(connection[i].ch_mutex,NULL); } pthread_mutex_lock(connection[i].ch_mutex); if (connection[i].ch_inuse == FALSE) { out = i; connection[out].ch_inuse = TRUE; connection[out].ch_errno = 0; connection[out].ch_socket = -1; connection[out].ch_errtxt = NULL; break; } pthread_mutex_unlock(connection[i].ch_mutex); } if (out < 0) { if (getenv("PBSDEBUG")) fprintf(stderr, "ALERT: cannot locate free channel\n"); /* FAILURE */ /* no need to unlock mutex here - in this case no connection was found */ return(PBSE_NOCONNECTS * -1); } /* get server host and port */ server = PBS_get_server(server, &server_port); if (server == NULL) { connection[out].ch_inuse = FALSE; pthread_mutex_unlock(connection[out].ch_mutex); if (getenv("PBSDEBUG")) fprintf(stderr, "ALERT: PBS_get_server() failed\n"); return(PBSE_NOSERVER * -1); } /* determine who we are */ pbs_current_uid = getuid(); if ((pw = getpwuid(pbs_current_uid)) == NULL) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ALERT: cannot get password info for uid %ld\n", (long)pbs_current_uid); } pthread_mutex_unlock(connection[out].ch_mutex); return(PBSE_SYSTEM * -1); } strcpy(pbs_current_user, pw->pw_name); pbs_server = server; /* set for error messages from commands */ #ifdef ENABLE_UNIX_SOCKETS /* determine if we want to use unix domain socket */ if (!strcmp(server, "localhost")) use_unixsock = 1; else if ((gethostname(hnamebuf, sizeof(hnamebuf) - 1) == 0) && !strcmp(hnamebuf, server)) use_unixsock = 1; /* NOTE: if any part of using unix domain sockets fails, * we just cleanup and try again with inet sockets */ /* get socket */ if (use_unixsock) { connection[out].ch_socket = socket(AF_UNIX, SOCK_STREAM, 0); if (connection[out].ch_socket < 0) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot create socket: errno=%d (%s)\n", errno, strerror(errno)); } connection[out].ch_inuse = FALSE; local_errno = PBSE_PROTOCOL; use_unixsock = 0; } } /* and connect... */ if (use_unixsock) { unserver_addr.sun_family = AF_UNIX; strcpy(unserver_addr.sun_path, TSOCK_PATH); if (connect( connection[out].ch_socket, (struct sockaddr *)&unserver_addr, (strlen(unserver_addr.sun_path) + sizeof(unserver_addr.sun_family))) < 0) { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; local_errno = errno; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot connect to server, errno=%d (%s)\n", errno, strerror(errno)); } use_unixsock = 0; /* will try again with inet socket */ } } if (use_unixsock) { if (!send_unix_creds(connection[out].ch_socket)) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot send unix creds to pbs_server: errno=%d (%s)\n", errno, strerror(errno)); } close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; local_errno = PBSE_PROTOCOL; use_unixsock = 0; /* will try again with inet socket */ } } #endif /* END ENABLE_UNIX_SOCKETS */ if (!use_unixsock) { /* at this point, either using unix sockets failed, or we determined not to * try */ connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); if (connection[out].ch_socket < 0) { if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot connect to server \"%s\", errno=%d (%s)\n", server, errno, strerror(errno)); } connection[out].ch_inuse = FALSE; pthread_mutex_unlock(connection[out].ch_mutex); return(PBSE_PROTOCOL * -1); } /* This is probably an IPv4 solution for the if_name and preferred_addr We need to see what ioctl call we need for IPv6 */ if_name = trq_get_if_name(); if (if_name) { rc = trq_set_preferred_network_interface(if_name, &preferred_addr); if (rc != PBSE_NONE) { fprintf(stderr, "could not set preferred network interface (%s): %d\n", if_name, rc); if(if_name) free(if_name); return(rc); } rc = bind(connection[out].ch_socket, &preferred_addr, sizeof(struct sockaddr)); if (rc < 0) { fprintf(stderr, "ERROR: could not bind preferred network interface (%s): errno: %d", if_name, errno); if (if_name) free(if_name); return(PBSE_SYSTEM * -1); } } /* we are done with if_name at this point. trq_get_if_name allocated space for it. We need to free it */ if (if_name) free(if_name); server_addr.sin_family = AF_INET; if (getaddrinfo(server, NULL, NULL, &addr_info) != 0) { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot get servername (%s) errno=%d (%s)\n", (server != NULL) ? server : "NULL", errno, strerror(errno)); } pthread_mutex_unlock(connection[out].ch_mutex); return(PBSE_BADHOST * -1); } server_addr.sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr; freeaddrinfo(addr_info); server_addr.sin_port = htons(server_port); if (connect( connection[out].ch_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot connect to server, errno=%d (%s)\n", errno, strerror(errno)); } pthread_mutex_unlock(connection[out].ch_mutex); return(errno * -1); } /* FIXME: is this necessary? Contributed by one user that fixes a problem, but doesn't fix the same problem for another user! */ #if 0 #if defined(__hpux) /*HP-UX : avoiding socket caching */ send(connection[out].ch_socket, '?', 1, MSG_OOB); #endif #endif #ifdef MUNGE_AUTH rc = PBSD_munge_authenticate(connection[out].ch_socket, out); if (rc != 0) { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; if (rc == PBSE_MUNGE_NOT_FOUND) { local_errno = PBSE_MUNGE_NOT_FOUND; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot find munge executable\n"); } } else { local_errno = PBSE_PERM; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot authenticate connection to server \"%s\", errno=%d (%s)\n", server, errno, strerror(errno)); } } pthread_mutex_unlock(connection[out].ch_mutex); return(-1 * local_errno); } #else /* new version of iff using daemon */ if ((ENABLE_TRUSTED_AUTH == FALSE) && ((rc = validate_socket(connection[out].ch_socket)) != PBSE_NONE)) { close(connection[out].ch_socket); connection[out].ch_inuse = FALSE; if (getenv("PBSDEBUG")) { fprintf(stderr, "ERROR: cannot authenticate connection to server \"%s\", errno=%d (%s)\n", server, rc, pbs_strerror(rc)); } local_errno = PBSE_SOCKET_FAULT; pthread_mutex_unlock(connection[out].ch_mutex); return(-1 * local_errno); } #endif /* ifdef MUNGE_AUTH */ } /* END if !use_unixsock */ /* setup DIS support routines for following pbs_* calls */ if ((ptr = getenv("PBSAPITIMEOUT")) != NULL) { pbs_tcp_timeout = strtol(ptr, NULL, 0); if (pbs_tcp_timeout <= 0) { pbs_tcp_timeout = 10800; /* set for 3 hour time out */ } } else { pbs_tcp_timeout = 10800; /* set for 3 hour time out */ } pthread_mutex_unlock(connection[out].ch_mutex); return(out); } /* END pbs_original_connect() */
/* validate_server: * * This function tries to find the currently active * pbs_server. If no server can be found the default * server is made the active server */ int validate_server( char *active_server_name, int t_server_port, char *ssh_key, char **sign_key) { int rc = PBSE_NONE; int sd; char server_name_list[PBS_MAXSERVERNAME*3+1]; char current_name[PBS_MAXSERVERNAME+1]; char *tp; char log_buf[LOCAL_LOG_BUF_SIZE]; /* First we try to connect to the pbs_server as indicated in active_server_name. If that fails we go through the server list. If that fails we stick with the active_server_name. If another server in teh server_name_list responds that will become the active_pbs_server */ if (active_server_name != NULL) rc = trq_simple_connect(active_server_name, t_server_port, &sd); else rc = PBSE_UNKREQ; /* If we don't have a server name we want to process everyting. */ if ( rc != PBSE_NONE) { int list_len; int i; unsigned int port; char *tmp_server; snprintf(server_name_list, sizeof(server_name_list), "%s", pbs_get_server_list()); list_len = csv_length(server_name_list); for (i = 0; i < list_len; i++) /* Try all server names in the list. */ { tp = csv_nth(server_name_list, i); if (tp && tp[0]) { /* Trim any leading space */ while(isspace(*tp)) tp++; memset(current_name, 0, sizeof(current_name)); snprintf(current_name, sizeof(current_name), "%s", tp); if (getenv("PBSDEBUG")) { fprintf(stderr, "pbs_connect attempting connection to server \"%s\"\n", current_name); } tmp_server = PBS_get_server(current_name, &port); rc = trq_simple_connect(tmp_server, port, &sd); if ( rc == PBSE_NONE) { trq_simple_disconnect(sd); fprintf(stderr, "changing active server to %s port %d\n", tmp_server, port); snprintf(active_pbs_server, sizeof(active_pbs_server), "%s", tmp_server); active_pbs_server_port = port; sprintf(log_buf, "Changing active server to %s port %d\n", tmp_server, port); log_event(PBSEVENT_CLIENTAUTH | PBSEVENT_FORCE, PBS_EVENTCLASS_TRQAUTHD, __func__, log_buf); break; } } } } else trq_simple_disconnect(sd); if (rc != PBSE_NONE) /* This only indicates no server is currently active. Go to default */ { fprintf(stderr, "Currently no servers active. Default server will be listed as active server. Error % d\n", rc); rc = PBSE_NONE; } fprintf(stderr, "Active server name: %s pbs_server port is: %d\n", active_pbs_server, active_pbs_server_port); return(rc); } /* END validate_server() */
/** * @brief * Open a connection with a pbs server. * Do not allow TCP to block us if Server host is down * At this point, this does not attempt to find a fail_over Server * * @param[in] server - specifies the server to which to connect * @param[in] tout - timeout value for select * * @return int * @retval >= 0 index to the internal connection table representing the * connection made. * @retval -1 error encountered in getting index */ int pbs_connect_noblk(char *server, int tout) { int out; int i; pbs_socklen_t l; int n; struct timeval tv; fd_set fdset; struct batch_reply *reply; char server_name[PBS_MAXSERVERNAME+1]; unsigned int server_port; struct addrinfo *aip, *pai; struct addrinfo hints; struct sockaddr_in *inp; short int connect_err = 0; struct sockaddr_in sockname; pbs_socklen_t socknamelen; #ifdef WIN32 int non_block = 1; struct sockaddr_in to_sock; struct sockaddr_in from_sock; #endif #ifndef WIN32 int nflg; int oflg; #endif /* initialize the thread context data, if not already initialized */ if (pbs_client_thread_init_thread_context() != 0) return -1; if (pbs_loadconf(0) == 0) return -1; /* get server host and port */ server = PBS_get_server(server, server_name, &server_port); if (server == NULL) { pbs_errno = PBSE_NOSERVER; return -1; } /* Reserve a connection state record */ if (pbs_client_thread_lock_conntable() != 0) return -1; out = -1; for (i=1;i<NCONNECTS;i++) { if (connection[i].ch_inuse) continue; out = i; connection[out].ch_inuse = 1; connection[out].ch_errno = 0; connection[out].ch_socket= -1; connection[out].ch_errtxt = NULL; break; } if (pbs_client_thread_unlock_conntable() != 0) return -1; /* pbs_errno set by the function */ if (out < 0) { pbs_errno = PBSE_NOCONNECTS; return -1; } /* get socket */ #ifdef WIN32 /* the following lousy hack is needed since the socket call needs */ /* SYSTEMROOT env variable properly set! */ if (getenv("SYSTEMROOT") == NULL) { setenv("SYSTEMROOT", "C:\\WINNT", 1); setenv("SystemRoot", "C:\\WINNT", 1); } connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); if (connection[out].ch_socket < 0) { setenv("SYSTEMROOT", "C:\\WINDOWS", 1); setenv("SystemRoot", "C:\\WINDOWS", 1); connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); } #else connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); #endif if (connection[out].ch_socket < 0) { connection[out].ch_inuse = 0; pbs_errno = ERRORNO; return -1; } /* set socket non-blocking */ #ifdef WIN32 if (ioctlsocket(connection[out].ch_socket, FIONBIO, &non_block) == SOCKET_ERROR) #else oflg = fcntl(connection[out].ch_socket, F_GETFL) & ~O_ACCMODE; nflg = oflg | O_NONBLOCK; if (fcntl(connection[out].ch_socket, F_SETFL, nflg) == -1) #endif goto err; /* and connect... */ strcpy(pbs_server, server); /* set for error messages from commands */ memset(&hints, 0, sizeof(struct addrinfo)); /* * Why do we use AF_UNSPEC rather than AF_INET? Some * implementations of getaddrinfo() will take an IPv6 * address and map it to an IPv4 one if we ask for AF_INET * only. We don't want that - we want only the addresses * that are genuinely, natively, IPv4 so we start with * AF_UNSPEC and filter ai_family below. */ hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (getaddrinfo(server, NULL, &hints, &pai) != 0) { CLOSESOCKET(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = PBSE_BADHOST; return -1; } for (aip = pai; aip != NULL; aip = aip->ai_next) { /* skip non-IPv4 addresses */ if (aip->ai_family == AF_INET) { inp = (struct sockaddr_in *) aip->ai_addr; break; } } if (aip == NULL) { /* treat no IPv4 addresses as getaddrinfo() failure */ CLOSESOCKET(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = PBSE_BADHOST; freeaddrinfo(pai); return -1; } else inp->sin_port = htons(server_port); if (connect(connection[out].ch_socket, aip->ai_addr, aip->ai_addrlen) < 0) { connect_err = 1; } if (connect_err == 1) { /* connect attempt failed */ pbs_errno = ERRORNO; switch (pbs_errno) { #ifdef WIN32 case WSAEWOULDBLOCK: #else case EINPROGRESS: case EWOULDBLOCK: #endif while (1) { FD_ZERO(&fdset); FD_SET(connection[out].ch_socket, &fdset); tv.tv_sec = tout; tv.tv_usec = 0; n = select(connection[out].ch_socket+1, NULL, &fdset, NULL, &tv); if (n > 0) { pbs_errno = 0; l = sizeof(pbs_errno); (void)getsockopt(connection[out].ch_socket, SOL_SOCKET, SO_ERROR, &pbs_errno, &l); if (pbs_errno == 0) break; else goto err; } if ((n < 0) && #ifdef WIN32 (ERRORNO == WSAEINTR) #else (ERRORNO == EINTR) #endif ) { continue; } else { goto err; } } break; default: err: CLOSESOCKET(connection[out].ch_socket); connection[out].ch_inuse = 0; freeaddrinfo(pai); return -1; /* cannot connect */ } } freeaddrinfo(pai); /* reset socket blocking */ #ifdef WIN32 non_block = 0; if (ioctlsocket(connection[out].ch_socket, FIONBIO, &non_block) == SOCKET_ERROR) #else if (fcntl(connection[out].ch_socket, F_SETFL, oflg) < 0) #endif goto err; /* * multiple threads cant get the same connection id above, * so no need to lock this piece of code */ /* setup connection level thread context */ if (pbs_client_thread_init_connect_context(out) != 0) { CLOSESOCKET(connection[out].ch_socket); connection[out].ch_inuse = 0; /* pbs_errno set by the pbs_connect_init_context routine */ return -1; } /* * even though the following is communication with server on * a connection handle, it does not need to be lock since * this connection handle has not be returned back yet to the client * so others threads cannot use it */ /* send "dummy" connect message */ DIS_tcp_setup(connection[out].ch_socket); if ((i = encode_DIS_ReqHdr(connection[out].ch_socket, PBS_BATCH_Connect, pbs_current_user)) || (i = encode_DIS_ReqExtend(connection[out].ch_socket, NULL))) { pbs_errno = PBSE_SYSTEM; return -1; } if (DIS_tcp_wflush(connection[out].ch_socket)) { pbs_errno = PBSE_SYSTEM; return -1; } reply = PBSD_rdrpy(out); PBSD_FreeReply(reply); /*do configured authentication (kerberos, pbs_iff, whatever)*/ /*Get the socket port for engage_authentication()*/ socknamelen = sizeof(sockname); if (getsockname(connection[out].ch_socket, (struct sockaddr *)&sockname, &socknamelen)) return -1; if (engage_authentication(connection[out].ch_socket, server, server_port, &sockname) == -1) { CLOSESOCKET(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = PBSE_PERM; return -1; } /* setup DIS support routines for following pbs_* calls */ DIS_tcp_setup(connection[out].ch_socket); pbs_tcp_timeout = PBS_DIS_TCP_TIMEOUT_VLONG; /* set for 3 hours */ return out; }
/** * @brief * Makes a PBS_BATCH_Connect request to 'server'. * * @param[in] server - the hostname of the pbs server to connect to. * @param[in] extend_data - a string to send as "extend" data. * * @return int * @retval >= 0 index to the internal connection table representing the * connection made. * @retval -1 error encountered setting up the connection. */ int __pbs_connect_extend(char *server, char *extend_data) { struct sockaddr_in server_addr; struct sockaddr_in my_sockaddr; int out; int i; int f; char *altservers[2]; int have_alt = 0; struct batch_reply *reply; char server_name[PBS_MAXSERVERNAME+1]; unsigned int server_port; struct sockaddr_in sockname; pbs_socklen_t socknamelen; #ifdef WIN32 struct sockaddr_in to_sock; struct sockaddr_in from_sock; #endif #ifndef WIN32 char pbsrc[_POSIX_PATH_MAX]; struct stat sb; int using_secondary = 0; #endif /* not WIN32 */ /* initialize the thread context data, if not already initialized */ if (pbs_client_thread_init_thread_context() != 0) return -1; if (pbs_loadconf(0) == 0) return -1; /* get server host and port */ server = PBS_get_server(server, server_name, &server_port); if (server == NULL) { pbs_errno = PBSE_NOSERVER; return -1; } if (pbs_conf.pbs_primary && pbs_conf.pbs_secondary) { /* failover configuered ... */ if (hostnmcmp(server, pbs_conf.pbs_primary) == 0) { have_alt = 1; /* We want to try the one last seen as "up" first to not */ /* have connection delays. If the primary was up, there */ /* is no .pbsrc.NAME file. If the last command connected */ /* to the Secondary, then it created the .pbsrc.USER file. */ /* see if already seen Primary down */ #ifdef WIN32 /* due to windows quirks, all try both in same order */ altservers[0] = pbs_conf.pbs_primary; altservers[1] = pbs_conf.pbs_secondary; #else (void)snprintf(pbsrc, _POSIX_PATH_MAX, "%s/.pbsrc.%s", pbs_conf.pbs_tmpdir, pbs_current_user); if (stat(pbsrc, &sb) == -1) { /* try primary first */ altservers[0] = pbs_conf.pbs_primary; altservers[1] = pbs_conf.pbs_secondary; using_secondary = 0; } else { /* try secondary first */ altservers[0] = pbs_conf.pbs_secondary; altservers[1] = pbs_conf.pbs_primary; using_secondary = 1; } #endif } } /* if specific host name declared for the host on which */ /* this client is running, get its address */ if (pbs_conf.pbs_public_host_name) { if (get_hostsockaddr(pbs_conf.pbs_public_host_name, &my_sockaddr) != 0) return -1; /* pbs_errno was set */ } /* Reserve a connection state record */ if (pbs_client_thread_lock_conntable() != 0) return -1; out = -1; for (i=1;i<NCONNECTS;i++) { if (connection[i].ch_inuse) continue; out = i; connection[out].ch_errno = 0; connection[out].ch_socket= -1; connection[out].ch_errtxt = NULL; connection[out].ch_inuse = 1; /* reserve the socket */ break; } if (pbs_client_thread_unlock_conntable() != 0) return -1; /* pbs_errno set by the function */ if (out < 0) { pbs_errno = PBSE_NOCONNECTS; return -1; } /* * connect to server ... * If attempt to connect fails and if Failover configured and * if attempting to connect to Primary, try the Secondary * if attempting to connect to Secondary, try the Primary */ for (i=0; i<(have_alt+1); ++i) { /* get socket */ #ifdef WIN32 /* the following lousy hack is needed since the socket call needs */ /* SYSTEMROOT env variable properly set! */ if (getenv("SYSTEMROOT") == NULL) { setenv("SYSTEMROOT", "C:\\WINNT", 1); setenv("SystemRoot", "C:\\WINNT", 1); } connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); if (connection[out].ch_socket < 0) { setenv("SYSTEMROOT", "C:\\WINDOWS", 1); setenv("SystemRoot", "C:\\WINDOWS", 1); connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); } #else connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0); #endif if (connection[out].ch_socket < 0) { connection[out].ch_inuse = 0; pbs_errno = errno; return -1; } /* and connect... */ if (have_alt) { server = altservers[i]; } strcpy(pbs_server, server); /* set for error messages from commands */ /* If a specific host name is defined which the client should use */ if (pbs_conf.pbs_public_host_name) { /* my address will be in my_sockaddr, bind the socket to it */ my_sockaddr.sin_port = 0; if (bind(connection[out].ch_socket, (struct sockaddr *)&my_sockaddr, sizeof(my_sockaddr)) != 0) { return -1; } } if (get_hostsockaddr(server, &server_addr) != 0) return -1; server_addr.sin_port = htons(server_port); if (connect(connection[out].ch_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == 0) { break; } else { /* connect attempt failed */ CLOSESOCKET(connection[out].ch_socket); pbs_errno = errno; } } if (i >= (have_alt+1)) { connection[out].ch_inuse = 0; return -1; /* cannot connect */ } #ifndef WIN32 if (have_alt && (i == 1)) { /* had to use the second listed server ... */ if (using_secondary == 1) { /* remove file that causes trying the Secondary first */ unlink(pbsrc); } else { /* create file that causes trying the Primary first */ f = open(pbsrc, O_WRONLY|O_CREAT, 0200); if (f != -1) (void)close(f); } } #endif /* setup connection level thread context */ if (pbs_client_thread_init_connect_context(out) != 0) { CLOSESOCKET(connection[out].ch_socket); connection[out].ch_inuse = 0; /* pbs_errno set by the pbs_connect_init_context routine */ return -1; } /* * No need for global lock now on, since rest of the code * is only communication on a connection handle. * But we dont need to lock the connection handle, since this * connection handle is not yet been returned to the client */ /* The following code was originally put in for HPUX systems to deal * with the issue where returning from the connect() call doesn't * mean the connection is complete. However, this has also been * experienced in some Linux ppc64 systems like js-2. Decision was * made to enable this harmless code for all architectures. * FIX: Need to use the socket to send * a message to complete the process. For IFF authentication there is * no leading authentication message needing to be sent on the client * socket, so will send a "dummy" message and discard the replyback. */ #if !defined(PBS_SECURITY ) || (PBS_SECURITY == STD ) DIS_tcp_setup(connection[out].ch_socket); if ((i = encode_DIS_ReqHdr(connection[out].ch_socket, PBS_BATCH_Connect, pbs_current_user)) || (i = encode_DIS_ReqExtend(connection[out].ch_socket, extend_data))) { pbs_errno = PBSE_SYSTEM; return -1; } if (DIS_tcp_wflush(connection[out].ch_socket)) { pbs_errno = PBSE_SYSTEM; return -1; } reply = PBSD_rdrpy(out); PBSD_FreeReply(reply); #endif /* PBS_SECURITY ... */ /*do configured authentication (kerberos, pbs_iff, whatever)*/ /*Get the socket port for engage_authentication() */ socknamelen = sizeof(sockname); if (getsockname(connection[out].ch_socket, (struct sockaddr *)&sockname, &socknamelen)) return -1; if (engage_authentication(connection[out].ch_socket, server, server_port, &sockname) == -1) { CLOSESOCKET(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = PBSE_PERM; return -1; } /* setup DIS support routines for following pbs_* calls */ DIS_tcp_setup(connection[out].ch_socket); pbs_tcp_timeout = PBS_DIS_TCP_TIMEOUT_VLONG; /* set for 3 hours */ /* * Disable Nagle's algorithm on the TCP connection to server. * Nagle's algorithm is hurting cmd-server communication. */ if (pbs_connection_set_nodelay(out) == -1) { CLOSESOCKET(connection[out].ch_socket); connection[out].ch_inuse = 0; pbs_errno = PBSE_SYSTEM; return -1; } return out; }