/* Generate the full name of a particular pk group. */ char *ssh_pk_group_object_name(SshPkGroupObject group) { unsigned char *str = NULL; if (group->diffie_hellman == NULL_FNPTR) ssh_dsprintf(&str, "%s", group->type->name); else ssh_dsprintf(&str, "%s{dh{%s}}", group->type->name, group->diffie_hellman->name); return (char *) str; }
/* This function takes a traffic selector and formats it as a string. This will return the allocated string inside the `str' argument. The `str' needs to be freed after it is no longer needed. Returns the number of characters written.*/ int ssh_ikev2_ts_to_string(char **str, SshIkev2PayloadTS ts) { return ssh_dsprintf((unsigned char **) str, "%@", ssh_ikev2_ts_render, ts); }
/* * Parse incoming socks connection from buffer. Consume the request * packet data from buffer. If everything is ok it allocates SocksInfo * strcture and store the request fields in it (sets * socks_version_number, command_code, ip, port, username). Returns * SSH_SOCKS_SUCCESS, SSH_SOCKS_TRY_AGAIN, or SSH_SOCKS_ERROR_*. If * anything other than SSH_SOCKS_SUCCESS is returned the socksinfo is * set to NULL. Use ssh_socks_free to free socksinfo data. */ SocksError ssh_socks_server_parse_open(SshBuffer buffer, SocksInfo *socksinfo) { unsigned char *data, *ip; unsigned long i, port; unsigned int version, cmd, ip_addr_len, atyp; unsigned char *username = NULL; size_t ret, len, bytes = 0; *socksinfo = NULL; len = ssh_buffer_len(buffer); data = ssh_buffer_ptr(buffer); if (len < 1) return SSH_SOCKS_TRY_AGAIN; version = data[0]; bytes++; if (version != 4 && version != 5) { SSH_DEBUG(2, ("Server gave us version %d.", version)); return SSH_SOCKS_ERROR_UNSUPPORTED_SOCKS_VERSION; } if (version == 4) { /* Check if enough data for header and name */ if (len < SOCKS4_COMMAND_SIZE + 1) { return SSH_SOCKS_TRY_AGAIN; } /* Find the end of username */ for (i = SOCKS4_COMMAND_SIZE; i < len; i++) { if (data[i] == '\0') break; } /* End of username not found, return either error or try_again */ if (i == len || data[i] != '\0') { if (len > SOCKS4_COMMAND_SIZE + SOCKS4_MAX_NAME_LEN) { return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } return SSH_SOCKS_TRY_AGAIN; } cmd = data[1]; port = SSH_GET_16BIT(&data[2]); ip_addr_len = 4; ip = ssh_memdup(&data[4], ip_addr_len); atyp = SSH_SOCKS5_ATYP_IPV4; if (ip == NULL) { SSH_DEBUG(2, ("Failed to allocate IP-address buffer.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } username = ssh_strdup((char *)(data + SOCKS4_COMMAND_SIZE)); bytes = SOCKS4_COMMAND_SIZE + strlen((char *) data + SOCKS4_COMMAND_SIZE) + 1; } else { unsigned char port_buf[2]; if (len - bytes < 3) return SSH_SOCKS_TRY_AGAIN; ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_CHAR(&cmd), SSH_DECODE_CHAR(NULL), /* RSV */ SSH_DECODE_CHAR(&atyp), SSH_FORMAT_END); if (ret <= 0) { SSH_DEBUG(2, ("Failed to decode command packet.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ret; if (atyp == SSH_SOCKS5_ATYP_IPV4) { SSH_DEBUG(4, ("SOCKS5 received address type IPV4.")); ip_addr_len = 4; } else if (atyp == SSH_SOCKS5_ATYP_IPV6) { SSH_DEBUG(4, ("SOCKS5 received address type IPV6.")); ip_addr_len = 16; } else if (atyp == SSH_SOCKS5_ATYP_FQDN) { if (len - bytes < 1) return SSH_SOCKS_TRY_AGAIN; ip_addr_len = *(data + bytes); if (ip_addr_len <= 0 || ip_addr_len >= 255) { SSH_DEBUG(2, ("Invalid FQDN address len %d.", ip_addr_len)); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } SSH_DEBUG(4, ("SOCKS5 received address type FQDN, len %d.", ip_addr_len)); bytes++; } else { SSH_DEBUG(2, ("Invalid address type %d.", atyp)); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } /* ip addr len + port */ if (len - bytes < ip_addr_len + 2) return SSH_SOCKS_TRY_AGAIN; ip = ssh_calloc(ip_addr_len + 1, sizeof(unsigned char)); if (ip == NULL) { SSH_DEBUG(2, ("Failed to allocate IP-address buffer.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_DATA(ip, ip_addr_len), SSH_DECODE_DATA(port_buf, 2), SSH_FORMAT_END); if (ret <= 0) { SSH_DEBUG(2, ("Failed to decode command packet.")); ssh_free(ip); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } port = SSH_GET_16BIT(port_buf); bytes += ret; } if ((*socksinfo = ssh_calloc(1, sizeof(struct SocksInfoRec))) == NULL) { SSH_DEBUG(2, ("Failed to allocate SocksInfo.")); ssh_free(ip); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } if (atyp == SSH_SOCKS5_ATYP_FQDN) { (*socksinfo)->ip = ip; } else { SshIpAddrStruct ip_addr; unsigned char buf[SSH_IP_ADDR_STRING_SIZE]; SSH_IP_DECODE(&ip_addr, ip, ip_addr_len); ssh_ipaddr_print(&ip_addr, buf, sizeof(buf)); (*socksinfo)->ip = ssh_memdup(buf, ssh_ustrlen(buf)); ssh_free(ip); if ((*socksinfo)->ip == NULL) { SSH_DEBUG(2, ("Failed to allocate final IP-addr buf.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } } (*socksinfo)->socks_version_number = version; (*socksinfo)->command_code = cmd; ssh_dsprintf(&(*socksinfo)->port, "%lu", port); (*socksinfo)->username = username; ssh_buffer_consume(buffer, bytes); SSH_DEBUG(5, ("Decoded %zd bytes.", bytes)); return SSH_SOCKS_SUCCESS; }
/* * Parse socks reply packet. Consume the reply packet data from buffer. * If the request was not granted (returns SSH_SOCKS_FAILED_*) the socket can * be immediately closed down (there will not be any additional data from the * socks server. * If the request is granted allocate socksinfo structure and store information * from request packet to there (sets socks_version_number, command_code, ip, * and port fields). * Use ssh_socks_free to free socksinfo data. */ SocksError ssh_socks_client_parse_reply(SshBuffer buffer, SocksInfo *socksinfo) { unsigned char *data, *ip_ptr, *port_ptr; unsigned char *username =NULL; unsigned long len, port, version; size_t bytes = 0; unsigned int cmd, atyp, ip_addr_len; if (socksinfo) *socksinfo = NULL; len = ssh_buffer_len(buffer); data = ssh_buffer_ptr(buffer); /* Check if enough data for version. */ if (len < 1) return SSH_SOCKS_TRY_AGAIN; version = data[0]; /* SOCKS4 replys have version number '0'. Go figure. */ if (version == 0) version = 4; bytes++; if (version != 4 && version != 5) { SSH_DEBUG(2, ("Server gave us version %ld.", version)); return SSH_SOCKS_ERROR_UNSUPPORTED_SOCKS_VERSION; } if (version == 4) { /* A SOCKS4 command reply is exactly 8 bytes long. */ if (len < 8) return SSH_SOCKS_TRY_AGAIN; SSH_DEBUG(2, ("Doing SOCKS4.")); bytes = 8; if (data[1] != SSH_SOCKS4_REPLY_GRANTED) { SocksError error = SSH_SOCKS_ERROR_PROTOCOL_ERROR; switch (data[1]) { case SSH_SOCKS4_REPLY_FAILED_REQUEST: error = SSH_SOCKS_FAILED_REQUEST; break; case SSH_SOCKS4_REPLY_FAILED_IDENTD: error = SSH_SOCKS_FAILED_IDENTD; break; case SSH_SOCKS4_REPLY_FAILED_USERNAME: error = SSH_SOCKS_FAILED_USERNAME; break; default: error = SSH_SOCKS_ERROR_PROTOCOL_ERROR; break; } ssh_buffer_consume(buffer, bytes); return error; } cmd = data[1]; port_ptr = &data[2]; ip_ptr = &data[4]; ip_addr_len = 4; atyp = SSH_SOCKS5_ATYP_IPV4; username = (unsigned char *)&data[8]; } else { size_t ret = 0L; /* SOCKS5. */ if (len - bytes < 3) return SSH_SOCKS_TRY_AGAIN; ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_CHAR(&cmd), SSH_DECODE_CHAR(NULL), /* RSV */ SSH_DECODE_CHAR(&atyp), SSH_FORMAT_END); if (ret == 0) { SSH_DEBUG(2, ("Decoding reply packet failed.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ret; if (atyp == SSH_SOCKS5_ATYP_IPV4) { ip_addr_len = 4; } else if (atyp == SSH_SOCKS5_ATYP_IPV6) { ip_addr_len = 16; } else if (atyp == SSH_SOCKS5_ATYP_FQDN) { if (len - bytes < 1) return SSH_SOCKS_TRY_AGAIN; ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_CHAR(&ip_addr_len), SSH_FORMAT_END); if (ret == 0) { SSH_DEBUG(2, ("Decoding FQDN hostname len failed.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ret; } else { SSH_DEBUG(2, ("Invalid address type %d.", atyp)); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } /* ip addr len + port (2 bytes) */ if (len - bytes < ip_addr_len + 2) return SSH_SOCKS_TRY_AGAIN; ip_ptr = data + bytes; if (ret == 0) { SSH_DEBUG(2, ("Decoding reply packet failed.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ip_addr_len; port_ptr = data + bytes; bytes += 2; SSH_DEBUG(2, ("Doing SOCKS5.")); if (cmd != SSH_SOCKS5_REPLY_SUCCESS) { SSH_DEBUG(2, ("Got reply %d from server.", cmd)); if (cmd < SSH_SOCKS5_REPLY_SUCCESS || cmd > SSH_SOCKS5_REPLY_ATYP_NOT_SUPPORTED) return SSH_SOCKS_ERROR_PROTOCOL_ERROR; return SSH_SOCKS_FAILED_REQUEST; } } if (socksinfo) { SshIpAddrStruct ip_addr; if ((*socksinfo = ssh_calloc(1, sizeof(SocksInfoStruct))) == NULL) { SSH_DEBUG(2, ("Couldn't allocate SocksInfo.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } memset(&ip_addr, 0, sizeof(ip_addr)); (*socksinfo)->socks_version_number = version; (*socksinfo)->command_code = cmd; port = SSH_GET_16BIT(port_ptr); ssh_dsprintf(&(*socksinfo)->port, "%lu", port); if (username) (*socksinfo)->username = ssh_strdup(username); else (*socksinfo)->username = NULL; if (atyp == SSH_SOCKS5_ATYP_FQDN) { (*socksinfo)->ip = ssh_calloc(ip_addr_len + 1, sizeof(char)); if ((*socksinfo)->ip) memmove((*socksinfo)->ip, ip_ptr, ip_addr_len); } else { unsigned char buf[SSH_IP_ADDR_STRING_SIZE]; SSH_IP_DECODE(&ip_addr, ip_ptr, ip_addr_len); ssh_ipaddr_print(&ip_addr, buf, sizeof(buf) - 1); (*socksinfo)->ip = ssh_strdup(buf); } } SSH_DEBUG(2, ("Decoded %zd bytes.", bytes)); ssh_buffer_consume(buffer, bytes); return SSH_SOCKS_SUCCESS; }
int main(int ac, char **av) { int opt, i; DIR *ssh2dir = NULL; char *ssh2dirname; Boolean dynamic_array = FALSE; struct dirent * cand; /* Save program name. */ if (strchr(av[0], '/')) av0 = strrchr(av[0], '/') + 1; else av0 = av[0]; user = ssh_user_initialize(NULL, FALSE); #ifdef WITH_PGP pgp_keyring = ssh_xstrdup(SSH_PGP_SECRET_KEY_FILE); #endif /* WITH_PGP */ action = ADD; while ((opt = ssh_getopt(ac, av, "ldDput:f:F:1LUNPI", NULL)) != EOF) { if (!ssh_optval) { usage(); exit(EXIT_STATUS_ERROR); } switch (opt) { case 'N': #ifdef WITH_PGP pgp_mode = PGP_KEY_NAME; #else /* WITH_PGP */ fprintf(stderr, "%s: PGP keys not supported.\n", av0); exit(EXIT_STATUS_ERROR); #endif /* WITH_PGP */ break; case 'P': #ifdef WITH_PGP pgp_mode = PGP_KEY_FINGERPRINT; #else /* WITH_PGP */ fprintf(stderr, "%s: PGP keys not supported.\n", av0); exit(EXIT_STATUS_ERROR); #endif /* WITH_PGP */ break; case 'I': #ifdef WITH_PGP pgp_mode = PGP_KEY_ID; #else /* WITH_PGP */ fprintf(stderr, "%s: PGP keys not supported.\n", av0); exit(EXIT_STATUS_ERROR); #endif /* WITH_PGP */ break; case 'R': #ifdef WITH_PGP ssh_xfree(pgp_keyring); pgp_keyring = ssh_xstrdup(ssh_optarg); #else /* WITH_PGP */ fprintf(stderr, "%s: PGP keys not supported.\n", av0); exit(EXIT_STATUS_ERROR); #endif /* WITH_PGP */ break; case 'l': action = LIST; break; case 'p': use_stdin = TRUE; break; case 'd': if (action == ADD_URL) action = DELETE_URL; else action = DELETE; break; case 'D': action = DELETE_ALL; break; case 't': if (ssh_optargnum) { key_timeout = (SshTime)(ssh_optargval * 60); } else { usage(); exit(EXIT_STATUS_ERROR); } have_attrs = TRUE; break; case 'f': if (ssh_optargnum) { path_limit = (SshUInt32)ssh_optargval; } else { usage(); exit(EXIT_STATUS_ERROR); } have_attrs = TRUE; break; case 'F': path_constraint = ssh_xstrdup(ssh_optarg); have_attrs = TRUE; break; case '1': forbid_compat = TRUE; have_attrs = TRUE; break; case 'u': if (action == DELETE) action = DELETE_URL; else action = ADD_URL; break; case 'L': action = LOCK; break; case 'U': action = UNLOCK; break; default: usage(); exit(EXIT_STATUS_ERROR); } } #ifdef WITH_PGP if (pgp_keyring[0] != '/') { char buf[1024]; snprintf(buf, sizeof (buf), "%s/%s/%s", ssh_user_dir(user), SSH_USER_DIR, pgp_keyring); ssh_xfree(pgp_keyring); pgp_keyring = ssh_xstrdup(buf); } #endif /* WITH_PGP */ files = &av[ssh_optind]; num_files = ac - ssh_optind; /* Fetch default from ~/.ssh2/id_* (the first that we happen to get) */ #define ID_PREFIX "id" if (num_files == 0 && action != LIST && action != DELETE_ALL && action != LOCK && action != UNLOCK) { #ifdef WITH_PGP if (pgp_mode != PGP_KEY_NONE) { fprintf(stderr, "%s: Nothing to do!\n", av0); exit(EXIT_STATUS_ERROR); } #endif /* WITH_PGP */ ssh_dsprintf(&ssh2dirname, "%s/%s", ssh_user_dir(user), SSH_USER_DIR); ssh2dir = opendir(ssh2dirname); if (!ssh2dir) { fprintf(stderr, "%s: Can't open directory \"%s\"", av0, ssh2dirname); exit(EXIT_STATUS_ERROR); } while ((cand = readdir(ssh2dir)) != NULL) { if ((strlen(cand->d_name) > strlen(ID_PREFIX)) && (strncmp(cand->d_name, ID_PREFIX, strlen(ID_PREFIX)) == 0) && ((strlen(cand->d_name) < 4) || (strcmp(cand->d_name + strlen(cand->d_name) - 4, ".pub") != 0)) && ((((cand->d_name)[strlen(ID_PREFIX)]) == '_') || (((cand->d_name)[strlen(ID_PREFIX)]) == '-') || (((cand->d_name)[strlen(ID_PREFIX)]) == '.') || (((cand->d_name)[strlen(ID_PREFIX)]) == '(') || (((cand->d_name)[strlen(ID_PREFIX)]) == '[') || (((cand->d_name)[strlen(ID_PREFIX)]) == '<') || (((cand->d_name)[strlen(ID_PREFIX)]) == '>'))) { files = ssh_xcalloc(2, sizeof(char *)); ssh_dsprintf(&files[0], "%s/%s", ssh2dirname, cand->d_name); ssh_xfree(ssh2dirname); num_files++; dynamic_array = TRUE; break; } } (void)closedir(ssh2dir); } signal(SIGPIPE, SIG_IGN); ssh_event_loop_initialize(); ssh_agent_open(agent_open_callback, NULL); ssh_event_loop_run(); ssh_event_loop_uninitialize(); if (dynamic_array) { for(i = 0; i < num_files ; i++) { ssh_xfree(files[i]); } ssh_xfree(files); } ssh_user_free(user, FALSE); exit(EXIT_STATUS_OK); }