<p>Neels Hofmeyr has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/13574">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add identifier sanitation for setting FSM instance ids<br><br>We often compose FSM instance IDs from context information, for example placing<br>an MSISDN string or IP:port information in the FSM instance id, using<br>osmo_fsm_inst_update_id_f(). This fails if any characters are contained that<br>don't pass osmo_identifier_valid(). Hence it is the task of the caller to make<br>sure only characters allowed in an FSM id are applied.<br><br>Provide API to trivially allow this by replacing illegal chars:<br>- osmo_identifier_sanitize_buf(), with access to the same set of illegal<br>  characters defined in utils.c,<br>- osmo_fsm_inst_update_id_f_sanitize() implicitly replaces non-identifier<br>  chars.<br><br>This makes it easy to add strings like '192.168.0.1:2342' or '+4987654321' to<br>an FSM instance id, without adding string mangling to each place that sets an<br>id; e.g. replacing with '-' to yield '192-168-0-1:2342' or '-4987654321'.<br><br>Change-Id: Ia40a6f3b2243c95fe428a080b938e11d8ab771a7<br>---<br>M include/osmocom/core/fsm.h<br>M include/osmocom/core/utils.h<br>M src/fsm.c<br>M src/utils.c<br>4 files changed, 54 insertions(+), 3 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/74/13574/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/core/fsm.h b/include/osmocom/core/fsm.h</span><br><span>index c9e1e0c..41d01a5 100644</span><br><span>--- a/include/osmocom/core/fsm.h</span><br><span>+++ b/include/osmocom/core/fsm.h</span><br><span>@@ -220,6 +220,7 @@</span><br><span> </span><br><span> int osmo_fsm_inst_update_id(struct osmo_fsm_inst *fi, const char *id);</span><br><span> int osmo_fsm_inst_update_id_f(struct osmo_fsm_inst *fi, const char *fmt, ...);</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_fsm_inst_update_id_f_sanitize(struct osmo_fsm_inst *fi, char replace_with, const char *fmt, ...);</span><br><span> </span><br><span> const char *osmo_fsm_event_name(struct osmo_fsm *fsm, uint32_t event);</span><br><span> const char *osmo_fsm_inst_name(struct osmo_fsm_inst *fi);</span><br><span>diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h</span><br><span>index ecb04b5..3f28eec 100644</span><br><span>--- a/include/osmocom/core/utils.h</span><br><span>+++ b/include/osmocom/core/utils.h</span><br><span>@@ -136,6 +136,7 @@</span><br><span> </span><br><span> bool osmo_identifier_valid(const char *str);</span><br><span> bool osmo_separated_identifiers_valid(const char *str, const char *sep_chars);</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_identifier_sanitize_buf(char *str, const char *sep_chars, char replace_with);</span><br><span> </span><br><span> const char *osmo_escape_str(const char *str, int len);</span><br><span> const char *osmo_escape_str_buf(const char *str, int in_len, char *buf, size_t bufsize);</span><br><span>diff --git a/src/fsm.c b/src/fsm.c</span><br><span>index b6912c6..c32767b 100644</span><br><span>--- a/src/fsm.c</span><br><span>+++ b/src/fsm.c</span><br><span>@@ -364,6 +364,35 @@</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Change id of the FSM instance using a string format, and ensuring a valid id.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Replace any characters that are not permitted as FSM identifier with replace_with.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] fi FSM instance.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] replace_with Character to use instead of non-permitted FSM id characters.</span><br><span style="color: hsl(120, 100%, 40%);">+ *                         Make sure to choose a legal character, e.g. '-'.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] fmt format string to compose new ID.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] ... variable argument list for format string.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns 0 if the ID was updated, otherwise -EINVAL.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_fsm_inst_update_id_f_sanitize(struct osmo_fsm_inst *fi, char replace_with, const char *fmt, ...)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       char *id = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      va_list ap;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!fmt)</span><br><span style="color: hsl(120, 100%, 40%);">+             return osmo_fsm_inst_update_id(fi, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   va_start(ap, fmt);</span><br><span style="color: hsl(120, 100%, 40%);">+    id = talloc_vasprintf(fi, fmt, ap);</span><br><span style="color: hsl(120, 100%, 40%);">+   va_end(ap);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_identifier_sanitize_buf(id, NULL, replace_with);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = osmo_fsm_inst_update_id(fi, id);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(id);</span><br><span style="color: hsl(120, 100%, 40%);">+      return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! allocate a new instance of a specified FSM</span><br><span>  *  \param[in] fsm Descriptor of the FSM</span><br><span>  *  \param[in] ctx talloc context from which to allocate memory</span><br><span>diff --git a/src/utils.c b/src/utils.c</span><br><span>index 7def0b8..8ea51ed 100644</span><br><span>--- a/src/utils.c</span><br><span>+++ b/src/utils.c</span><br><span>@@ -510,6 +510,8 @@</span><br><span>      return true;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static const char osmo_identifier_illegal_chars[] = "., {}[]()<>|~\\^`'\"?=;/+*&%$#!";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Determine if a given identifier is valid, i.e. doesn't contain illegal chars</span><br><span>  *  \param[in] str String to validate</span><br><span>  *  \param[in] sep_chars Permitted separation characters between identifiers.</span><br><span>@@ -518,7 +520,6 @@</span><br><span> bool osmo_separated_identifiers_valid(const char *str, const char *sep_chars)</span><br><span> {</span><br><span>   /* characters that are illegal in names */</span><br><span style="color: hsl(0, 100%, 40%);">-      static const char illegal_chars[] = "., {}[]()<>|~\\^`'\"?=;/+*&%$#!";</span><br><span>  unsigned int i;</span><br><span>      size_t len;</span><br><span> </span><br><span>@@ -535,7 +536,7 @@</span><br><span>                if (!isprint((int)str[i]))</span><br><span>                   return false;</span><br><span>                /* check for some explicit reserved control characters */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (strchr(illegal_chars, str[i]))</span><br><span style="color: hsl(120, 100%, 40%);">+            if (strchr(osmo_identifier_illegal_chars, str[i]))</span><br><span>                   return false;</span><br><span>        }</span><br><span> </span><br><span>@@ -551,7 +552,26 @@</span><br><span>         return osmo_separated_identifiers_valid(str, NULL);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! Return the string with all non-printable characters escapeda, in user-supplied buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Replace characters in the given string buffer so that it is guaranteed to pass osmo_separated_identifiers_valid().</span><br><span style="color: hsl(120, 100%, 40%);">+ * To guarantee passing osmo_separated_identifiers_valid(), replace_with must not itself be an illegal character. If in</span><br><span style="color: hsl(120, 100%, 40%);">+ * doubt, use '-'.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[inout] str  Identifier to sanitize, must be nul terminated and in a writable buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] sep_chars  Additional characters that are allowed besides osmo_identifier_illegal_chars.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] replace_with  Replace any illegal characters with this character.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_identifier_sanitize_buf(char *str, const char *sep_chars, char replace_with)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  char *pos;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!str)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       for (pos = str; *pos; pos++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (strchr(osmo_identifier_illegal_chars, *pos)</span><br><span style="color: hsl(120, 100%, 40%);">+                   || (sep_chars && strchr(sep_chars, *pos)))</span><br><span style="color: hsl(120, 100%, 40%);">+                        *pos = replace_with;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return the string with all non-printable characters escaped.</span><br><span>  * \param[in] str  A string that may contain any characters.</span><br><span>  * \param[in] len  Pass -1 to print until nul char, or >= 0 to force a length.</span><br><span>  * \param[inout] buf  string buffer to write escaped characters to.</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13574">change 13574</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/13574"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ia40a6f3b2243c95fe428a080b938e11d8ab771a7 </div>
<div style="display:none"> Gerrit-Change-Number: 13574 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>