QString stringPrepare(const Stringprep_profile *AProfile, const QString &AString) { QByteArray buffer = AString.toUtf8(); if (!buffer.isEmpty() && buffer.size()<1024) { buffer.reserve(1024); if (stringprep(buffer.data(),buffer.capacity(),(Stringprep_profile_flags)0, AProfile) == STRINGPREP_OK) return QString::fromUtf8(buffer.constData()); } return QString::null; }
/*! * \brief if necessary libraries are present this function converts the input * to utf8 and normalizes it. * \param s The input string * \return Returns a newly allocated zero-terminated string. */ char *normalize( char *s ) { char *buf; #ifdef HAVE_LIBIDN int bufsize, rc; char *utf8; traceLog(LOG_INFO,"Doing stringprep on %s", s); /* stringprep_locale_charset(); */ utf8 = stringprep_locale_to_utf8(s); bufsize = strlen(utf8) * 2; buf = (char *) Malloc ( bufsize * sizeof( char ) ); strcpy(buf,utf8); rc = stringprep (buf, bufsize, 0, stringprep_nameprep); if (rc != STRINGPREP_OK) { traceLog(LOG_INFO,"Stringprep failed with rc %d", rc); Free(buf); buf = utf8; } else Free(utf8); traceLog(LOG_INFO,"result %s", buf); #else buf = Strdup(s); #endif return buf; }
/* Given a UTF-8 password string, convert it to the canonical form * defined by SASLprep (RFC 4013). This is a permissive implementation, * suitable for verifying existing passwords but not for creating new * ones -- if you want to create a new password, you'll need to add a * strict mode that returns stringprep errors to the user, and uses the * STRINGPREP_NO_UNASSIGNED flag to disallow unassigned characters. * <string> .saslprep <string> */ static int zsaslprep(i_ctx_t *i_ctx_p) { os_ptr op = osp; uint input_size = r_size(op); byte *buffer; uint buffer_size; uint output_size; Stringprep_rc err; check_read_type(*op, t_string); /* According to http://unicode.org/faq/normalization.html, converting * a UTF-8 string to normalization form KC has a worst-case expansion * factor of 11, so we allocate 11 times the length of the string plus * 1 for the NUL terminator. If somehow that's still not big enough, * stringprep will return STRINGPREP_TOO_SMALL_BUFFER; there's no * danger of corrupting memory. */ buffer_size = input_size * 11 + 1; buffer = ialloc_string(buffer_size, "saslprep result"); if (buffer == 0) return_error(e_VMerror); memcpy(buffer, op->value.bytes, input_size); buffer[input_size] = '\0'; err = stringprep((char *)buffer, buffer_size, 0, stringprep_saslprep); if (err != STRINGPREP_OK) { ifree_string(buffer, buffer_size, "saslprep result"); /* Since we're just verifying the password to an existing * document here, we don't care about "invalid input" errors * like STRINGPREP_CONTAINS_PROHIBITED. In these cases, we * ignore the error and return the original string unchanged -- * chances are it's not the right password anyway, and if it * is we shouldn't gratuitously fail to decrypt the document. * * On the other hand, errors like STRINGPREP_NFKC_FAILED are * real errors, and should be returned to the user. * * Fortunately, the stringprep error codes are sorted to make * this easy: the errors we want to ignore are the ones with * codes less than 100. */ if ((int)err < 100) return 0; return_error(e_ioerror); } output_size = strlen((char *)buffer); buffer = iresize_string(buffer, buffer_size, output_size, "saslprep result"); /* can't fail */ make_string(op, a_all | icurrent_space, output_size, buffer); return 0; }
/** * Applies a Stringprep profile to a string. This function does the actual * work behind nodeprep, nameprep and resourceprep. * @param s The string to apply the profile to. * @param out Contains the prepped string if prepping was successful, else untouched. * @param profile The Stringprep profile to apply. * @return Returns @b true if prepping was successful, @b false otherwise. */ static bool prepare( const std::string& s, std::string& out, const Stringprep_profile* profile ) { if( s.empty() || s.length() > JID_PORTION_SIZE ) return false; char* p = static_cast<char*>( calloc( JID_PORTION_SIZE, sizeof( char ) ) ); strncpy( p, s.c_str(), s.length() ); int rc = stringprep( p, JID_PORTION_SIZE, static_cast<Stringprep_profile_flags>( 0 ), profile ); if( rc == STRINGPREP_OK ) out = p; free( p ); return rc == STRINGPREP_OK; }
int main (void) { char buf[BUFSIZ]; char *p; int rc; size_t i; setlocale (LC_ALL, ""); printf ("Input string encoded as `%s': ", stringprep_locale_charset ()); fflush (stdout); if (!fgets (buf, BUFSIZ, stdin)) perror ("fgets"); buf[strlen (buf) - 1] = '\0'; printf ("Before locale2utf8 (length %ld): ", (long int) strlen (buf)); for (i = 0; i < strlen (buf); i++) printf ("%02x ", buf[i] & 0xFF); printf ("\n"); p = stringprep_locale_to_utf8 (buf); if (p) { strcpy (buf, p); free (p); } else printf ("Could not convert string to UTF-8, continuing anyway...\n"); printf ("Before stringprep (length %ld): ", (long int) strlen (buf)); for (i = 0; i < strlen (buf); i++) printf ("%02x ", buf[i] & 0xFF); printf ("\n"); rc = stringprep (buf, BUFSIZ, 0, stringprep_nameprep); if (rc != STRINGPREP_OK) printf ("Stringprep failed (%d): %s\n", rc, stringprep_strerror (rc)); else { printf ("After stringprep (length %ld): ", (long int) strlen (buf)); for (i = 0; i < strlen (buf); i++) printf ("%02x ", buf[i] & 0xFF); printf ("\n"); } return 0; }
char * getdns_convert_ulabel_to_alabel(const char *ulabel) { #ifdef HAVE_LIBIDN int ret; char *buf; char *prepped; char *prepped2; if (ulabel == NULL) return 0; prepped2 = malloc(BUFSIZ); if(!prepped2) return 0; setlocale(LC_ALL, ""); if ((prepped = stringprep_locale_to_utf8(ulabel)) == 0) { /* convert to utf8 fails, which it can, but continue anyway */ if(strlen(ulabel)+1 > BUFSIZ) { free(prepped2); return 0; } memcpy(prepped2, ulabel, strlen(ulabel)+1); } else { if(strlen(prepped)+1 > BUFSIZ) { free(prepped); free(prepped2); return 0; } memcpy(prepped2, prepped, strlen(prepped)+1); free(prepped); } if ((ret = stringprep(prepped2, BUFSIZ, 0, stringprep_nameprep)) != STRINGPREP_OK) { free(prepped2); return 0; } if ((ret = idna_to_ascii_8z(prepped2, &buf, 0)) != IDNA_SUCCESS) { free(prepped2); return 0; } free(prepped2); return buf; #else return NULL; #endif }
/** * stringprep_profile - prepare internationalized string * @in: input array with UTF-8 string to prepare. * @out: output variable with pointer to newly allocate string. * @profile: name of stringprep profile to use. * @flags: a #Stringprep_profile_flags value, or 0. * * Prepare the input zero terminated UTF-8 string according to the * stringprep profile, and return the result in a newly allocated * variable. * * Note that you must convert strings entered in the systems locale * into UTF-8 before using this function, see * stringprep_locale_to_utf8(). * * The output @out variable must be deallocated by the caller. * * The @flags are one of #Stringprep_profile_flags values, or 0. * * The @profile specifies the name of the stringprep profile to use. * It must be one of the internally supported stringprep profiles. * * Return value: Returns %STRINGPREP_OK iff successful, or an error code. **/ int stringprep_profile (const char *in, char **out, const char *profile, Stringprep_profile_flags flags) { const Stringprep_profiles *p; char *str = NULL; size_t len = strlen (in) + 1; int rc; for (p = &stringprep_profiles[0]; p->name; p++) if (strcmp (p->name, profile) == 0) break; if (!p || !p->name || !p->tables) return STRINGPREP_UNKNOWN_PROFILE; do { if (str) free (str); str = (char *) malloc (len); if (str == NULL) return STRINGPREP_MALLOC_ERROR; strcpy (str, in); rc = stringprep (str, len, flags, p->tables); len += 50; } while (rc == STRINGPREP_TOO_SMALL_BUFFER); if (rc == STRINGPREP_OK) *out = str; else free (str); return rc; }
char *jabber_saslprep(const char *in) { #ifdef USE_IDN char *out; g_return_val_if_fail(in != NULL, NULL); g_return_val_if_fail(strlen(in) <= sizeof(idn_buffer) - 1, NULL); strncpy(idn_buffer, in, sizeof(idn_buffer) - 1); idn_buffer[sizeof(idn_buffer) - 1] = '\0'; if (STRINGPREP_OK != stringprep(idn_buffer, sizeof(idn_buffer), 0, stringprep_saslprep)) { memset(idn_buffer, 0, sizeof(idn_buffer)); return NULL; } out = g_strdup(idn_buffer); memset(idn_buffer, 0, sizeof(idn_buffer)); return out; #else /* USE_IDN */ /* TODO: Something better than disallowing all non-ASCII characters */ /* TODO: Is this even correct? */ const guchar *c; c = (const guchar *)in; for ( ; *c; ++c) { if (*c > 0x7f || /* Non-ASCII characters */ *c == 0x7f || /* ASCII Delete character */ (*c < 0x20 && *c != '\t' && *c != '\n' && *c != '\r')) /* ASCII control characters */ return NULL; } return g_strdup(in); #endif /* USE_IDN */ }
/** * caching wrapper around a stringprep function * * @param in_out_buffer buffer containing what has to be stringpreped and that gets the result * @param max_len size of the buffer * @param cache the used cache, defining also the used stringprep profile * @return the return code of the stringprep call */ static int _jid_cached_stringprep(char *in_out_buffer, int max_len, _jid_prep_cache_t cache) { _jid_prep_entry_t preped; int result = STRINGPREP_OK; /* check that the cache already exists * we can not do anything as we don't know which profile has to be used */ if (cache == NULL) { return STRINGPREP_UNKNOWN_PROFILE; } /* is there something that has to be stringpreped? */ if (in_out_buffer == NULL) { return STRINGPREP_OK; } /* acquire the lock on the cache */ g_mutex_lock(cache->mutex); /* check if the requested preparation has already been done */ preped = (_jid_prep_entry_t)g_hash_table_lookup(cache->hashtable, in_out_buffer); if (preped != NULL) { /* we already prepared this argument */ if (preped->size <= max_len) { /* we can use the result */ /* update the statistic */ preped->used_count++; preped->last_used = time(NULL); /* do we need to copy the result? */ if (preped->preped != NULL) { /* copy the result */ strcpy(in_out_buffer, preped->preped); } result = STRINGPREP_OK; } else { /* we need a bigger buffer */ result = STRINGPREP_TOO_SMALL_BUFFER; } /* we're done, release the lock on the cache */ g_mutex_unlock(cache->mutex); } else { char *original; /* stringprep needs time, release the lock on the cache for the meantime */ g_mutex_unlock(cache->mutex); /* we have to keep the key */ original = strdup(in_out_buffer); /* try to prepare the string */ result = stringprep(in_out_buffer, max_len, STRINGPREP_NO_UNASSIGNED, cache->profile); /* did we manage to prepare the string? */ if (result == STRINGPREP_OK && original != NULL) { /* generate an entry for the cache */ preped = (_jid_prep_entry_t)malloc(sizeof(struct _jid_prep_entry_st)); if (preped != NULL) { /* has there been modified something? */ if (j_strcmp(in_out_buffer, original) == 0) { /* no, we don't need to store a copy of the original string */ preped->preped = NULL; } else { /* yes, store the stringpreped string */ preped->preped = strdup(in_out_buffer); } preped->last_used = time(NULL); preped->used_count = 1; preped->size = strlen(in_out_buffer)+1; /* acquire the lock on the cache again */ g_mutex_lock(cache->mutex); /* store the entry in the cache */ g_hash_table_insert(cache->hashtable, original, preped); /* we're done, release the lock on the cache */ g_mutex_unlock(cache->mutex); } else { /* we don't need the copy of the key, if there is no memory to store it */ free(original); } } else { /* we don't need the copy of the original value */ if (original != NULL) free(original); } } return result; }
SilcStringprepStatus silc_stringprep(const unsigned char *bin, SilcUInt32 bin_len, SilcStringEncoding bin_encoding, const char *profile_name, SilcStringprepFlags flags, unsigned char **out, SilcUInt32 *out_len, SilcStringEncoding out_encoding) { Stringprep_profile_flags f = 0; const Stringprep_profile *profile; unsigned char *utf8s; SilcUInt32 utf8s_len; int ret; SILC_LOG_DEBUG(("Preparing string")); if (!bin || !bin_len || !profile_name) return SILC_STRINGPREP_ERR; /* Convert string to UTF-8 */ utf8s_len = silc_utf8_encoded_len(bin, bin_len, bin_encoding); if (!utf8s_len) return SILC_STRINGPREP_ERR_ENCODING; utf8s = silc_calloc(utf8s_len + 1, sizeof(*utf8s)); if (!utf8s) return SILC_STRINGPREP_ERR_OUT_OF_MEMORY; silc_utf8_encode(bin, bin_len, bin_encoding, utf8s, utf8s_len); /* Check profile. */ if (!strcmp(profile_name, SILC_IDENTIFIER_PREP)) profile = stringprep_silc_identifier_prep; else if (!strcmp(profile_name, SILC_IDENTIFIER_CH_PREP)) profile = stringprep_silc_identifier_ch_prep; else if (!strcmp(profile_name, SILC_IDENTIFIERC_PREP)) profile = stringprep_silc_identifierc_prep; else if (!strcmp(profile_name, SILC_CASEFOLD_PREP)) profile = stringprep_silc_casefold_prep; else return SILC_STRINGPREP_ERR_UNSUP_PROFILE; /* Translate flags */ if (!(flags & SILC_STRINGPREP_ALLOW_UNASSIGNED)) f |= STRINGPREP_NO_UNASSIGNED; /* Prepare */ ret = stringprep((char *)utf8s, utf8s_len, f, profile); SILC_LOG_DEBUG(("stringprep() return %d", ret)); /* Since the stringprep() doesn't allocate returned buffer, and stringprep_profile() doesn't do it correctly, we can't know how much space we must have for the conversion. Allocate more if it fails, and try again. */ if (ret == STRINGPREP_TOO_SMALL_BUFFER) { utf8s = silc_realloc(utf8s, sizeof(*utf8s) * ((utf8s_len * 2) + 1)); if (!utf8s) return SILC_STRINGPREP_ERR_OUT_OF_MEMORY; memset(utf8s + utf8s_len + 1, 0, utf8s_len); ret = stringprep((char *)utf8s, utf8s_len * 2, f, profile); SILC_LOG_DEBUG(("stringprep() return %d", ret)); } switch (ret) { case STRINGPREP_OK: ret = SILC_STRINGPREP_OK; break; case STRINGPREP_CONTAINS_UNASSIGNED: ret = SILC_STRINGPREP_ERR_UNASSIGNED; break; case STRINGPREP_CONTAINS_PROHIBITED: ret = SILC_STRINGPREP_ERR_PROHIBITED; break; case STRINGPREP_BIDI_BOTH_L_AND_RAL: ret = SILC_STRINGPREP_ERR_BIDI_RAL_WITH_L; break; case STRINGPREP_BIDI_LEADTRAIL_NOT_RAL: ret = SILC_STRINGPREP_ERR_BIDI_RAL; break; case STRINGPREP_BIDI_CONTAINS_PROHIBITED: ret = SILC_STRINGPREP_ERR_BIDI_PROHIBITED; break; case STRINGPREP_UNKNOWN_PROFILE: ret = SILC_STRINGPREP_ERR_UNSUP_PROFILE; break; case STRINGPREP_MALLOC_ERROR: ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY; break; default: ret = SILC_STRINGPREP_ERR; break; } /* Convert to desired output character encoding */ if (ret == SILC_STRINGPREP_OK) { if (out && out_len) { if (out_encoding != SILC_STRING_UTF8) { *out_len = silc_utf8_decoded_len(utf8s, strlen(utf8s), out_encoding); if (*out_len) { *out = silc_calloc(*out_len + 1, sizeof(**out)); if (*out) { silc_utf8_decode(utf8s, strlen(utf8s), out_encoding, *out, *out_len); } else { ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY; } } else { ret = SILC_STRINGPREP_ERR_ENCODING; } } else { *out_len = strlen(utf8s); *out = silc_memdup(utf8s, *out_len); } } } silc_free(utf8s); return (SilcStringprepStatus)ret; }