diff options
| -rw-r--r-- | src/analysis/db/auth.c | 49 | ||||
| -rw-r--r-- | src/analysis/db/auth.h | 3 | ||||
| -rw-r--r-- | src/analysis/db/certs.c | 109 | ||||
| -rw-r--r-- | src/analysis/db/certs.h | 3 | ||||
| -rw-r--r-- | src/gui/dialogs/identity.c | 111 | ||||
| -rw-r--r-- | src/gui/dialogs/identity.ui | 119 | 
6 files changed, 301 insertions, 93 deletions
| diff --git a/src/analysis/db/auth.c b/src/analysis/db/auth.c index af51af6..5e62f58 100644 --- a/src/analysis/db/auth.c +++ b/src/analysis/db/auth.c @@ -209,6 +209,38 @@ static char *get_cert_storage_directory(const char *outdir, const char *host, co  /******************************************************************************  *                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Détermine la désignation par défaut de l'usager.             * +*                                                                             * +*  Retour      : Nom déterminé à libérer de la mémoire.                       * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +char *get_default_username(void) +{ +    char *result;                           /* Désignation à retourner     */ +    uid_t uid;                              /* Identifiant d'utilisateur   */ +    struct passwd *pw;                      /* Indications sur l'usager    */ + +    uid = geteuid(); +    pw = getpwuid(uid); + +    if (pw != NULL) +        result = strdup(pw->pw_name); + +    else +        result = strdup("anonymous"); + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : valid   = durée de validité des certificats.                 *  *                entries = éléments d'identité à utiliser pour l'opération.   *  *                                                                             * @@ -224,8 +256,6 @@ bool setup_client_identity(unsigned long valid, x509_entries *entries)  {      bool result;                            /* Bilan de l'opération        */      char *working;                          /* Répertoire pour le client   */ -    uid_t uid;                              /* Identifiant d'utilisateur   */ -    struct passwd *pw;                      /* Indications sur l'usager    */      working = get_db_working_directory("clients", NULL, NULL, NULL); @@ -235,18 +265,11 @@ bool setup_client_identity(unsigned long valid, x509_entries *entries)      {          if (entries->common_name == NULL)          { -            uid = geteuid(); -            pw = getpwuid(uid); - -            if (pw != NULL) -            { -                log_variadic_message(LMT_WARNING, -                                     _("Replaced the empty identity common name with '%s'"), -                                     pw->pw_name); - -                entries->common_name = strdup(pw->pw_name); +            entries->common_name = get_default_username(); -            } +            log_variadic_message(LMT_WARNING, +                                 _("Replaced the empty identity common name with '%s'"), +                                 entries->common_name);          } diff --git a/src/analysis/db/auth.h b/src/analysis/db/auth.h index 4db7af7..4464244 100644 --- a/src/analysis/db/auth.h +++ b/src/analysis/db/auth.h @@ -39,6 +39,9 @@ bool build_internal_server_socket(struct sockaddr_un *);  /* Fournit le répertoire de travail pour les données d'analyse. */  char *get_db_working_directory(const char *, const char *, const char *, const char *); +/* Détermine la désignation par défaut de l'usager. */ +char *get_default_username(void); +  /* Etablit une base pour l'identité de l'utilisateur. */  bool setup_client_identity(unsigned long, x509_entries *); diff --git a/src/analysis/db/certs.c b/src/analysis/db/certs.c index a333d9a..107b7b9 100644 --- a/src/analysis/db/certs.c +++ b/src/analysis/db/certs.c @@ -24,6 +24,7 @@  #include "certs.h" +#include <assert.h>  #include <glib.h>  #include <malloc.h>  #include <stdio.h> @@ -258,7 +259,7 @@ bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid,      EVP_PKEY *pk;                           /* Enveloppe pour clef publique*/      int ret;                                /* Bilan d'un appel            */      X509 *x509;                             /* Certificat X509 à définir   */ -    X509_NAME *name;                        /* Désignation du certificat   */ +    X509_NAME *subject;                     /* SUjet du certificat         */      char *filename;                         /* Chemin d'accès à un fichier */      FILE *stream;                           /* Flux ouvert en écriture     */ @@ -288,14 +289,14 @@ bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid,      /* Etablissement d'une identité */ -    name = X509_get_subject_name(x509); +    subject = X509_get_subject_name(x509);  #define SET_NAME_ENTRY(key, value)                                                          \      do                                                                                      \      {                                                                                       \          if (entries->value != NULL)                                                         \          {                                                                                   \ -            ret = X509_NAME_add_entry_by_txt(name, key, MBSTRING_UTF8,                      \ +            ret = X509_NAME_add_entry_by_txt(subject, key, MBSTRING_UTF8,                   \                                               (unsigned char *)entries->value, -1, -1, 0);   \              if (ret != 1) goto ca_failed;                                                   \          }                                                                                   \ @@ -316,7 +317,7 @@ bool build_keys_and_ca(const char *dir, const char *label, unsigned long valid,  #undef SET_NAME_ENTRY -    ret = X509_set_issuer_name(x509, name); +    ret = X509_set_issuer_name(x509, subject);      if (ret != 1) goto ca_failed;      /* Extensions */ @@ -461,7 +462,7 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri      EVP_PKEY *pk;                           /* Enveloppe pour clef publique*/      int ret;                                /* Bilan d'un appel            */      X509_REQ *x509;                         /* Certificat X509 à définir   */ -    X509_NAME *name;                        /* Désignation du certificat   */ +    X509_NAME *subject;                     /* Sujet du certificat         */      STACK_OF(X509_EXTENSION) *exts;         /* Extensions du certificat    */      char *filename;                         /* Chemin d'accès à un fichier */      FILE *stream;                           /* Flux ouvert en écriture     */ @@ -483,14 +484,14 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri      /* Etablissement d'une identité */ -    name = X509_REQ_get_subject_name(x509); +    subject = X509_REQ_get_subject_name(x509);  #define SET_NAME_ENTRY(key, value)                                                          \      do                                                                                      \      {                                                                                       \          if (entries->value != NULL)                                                         \          {                                                                                   \ -            ret = X509_NAME_add_entry_by_txt(name, key, MBSTRING_UTF8,                      \ +            ret = X509_NAME_add_entry_by_txt(subject, key, MBSTRING_UTF8,                   \                                               (unsigned char *)entries->value, -1, -1, 0);   \              if (ret != 1) goto req_failed;                                                  \          }                                                                                   \ @@ -603,6 +604,88 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri  /******************************************************************************  *                                                                             * +*  Paramètres  : csr     = fichier contenant le certificat à signer.          * +*                entries = éléments de l'identité constituée. [OUT]           * +*                                                                             * +*  Description : Recharge l'identité inscrite dans une requête de signature.  * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool load_identity_from_request(const char *csr, x509_entries *entries) +{ +    bool result;                            /* Bilan à retourner           */ +    FILE *stream;                           /* Flux ouvert en lecture      */ +    X509_REQ *req;                          /* Certificat X509 à signer    */ +    X509_NAME *subject;                     /* Sujet du certificat         */ +    int length;                             /* Taille du champ visé        */ + +    result = false; + +    memset(entries, 0, sizeof(*entries)); + +    /* Chargement de la requête */ + +    stream = fopen(csr, "rb"); +    if (stream == NULL) goto csr_read_failed; + +    req = PEM_read_X509_REQ(stream, NULL, NULL, NULL); + +    fclose(stream); + +    if (req == NULL) +    { +        log_variadic_message(LMT_ERROR, _("Unable to read the certificate signing request from '%s'"), csr); +        goto csr_read_failed; +    } + +    /* Recherche des éléments */ + +    subject = X509_REQ_get_subject_name(req); + +#define GET_NAME_ENTRY(key, value)                                                          \ +    do                                                                                      \ +    {                                                                                       \ +        length = X509_NAME_get_text_by_NID(subject, key, NULL, -1);                         \ +        if (length != -1)                                                                   \ +        {                                                                                   \ +            entries->value = malloc((length + 1) * sizeof(char));                           \ +            length = X509_NAME_get_text_by_NID(subject, key, entries->value, length + 1);   \ +            assert(length != -1);                                                           \ +        }                                                                                   \ +    }                                                                                       \ +    while (0) + +    GET_NAME_ENTRY(NID_countryName, country); + +    GET_NAME_ENTRY(NID_stateOrProvinceName, state); + +    GET_NAME_ENTRY(NID_localityName, locality); + +    GET_NAME_ENTRY(NID_organizationName, organisation); + +    GET_NAME_ENTRY(NID_organizationalUnitName, organisational_unit); + +    GET_NAME_ENTRY(NID_commonName, common_name); + +#undef GET_NAME_ENTRY + +    X509_REQ_free(req); + +    result = true; + + csr_read_failed: + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : csr    = fichier contenant le certificat à signer.           *  *                cacert = fichier contenant le certificat de l'autorité.      *  *                cakey  = fichier contenant la clef privée du CA.             * @@ -619,14 +702,14 @@ bool build_keys_and_request(const char *dir, const char *label, const x509_entri  bool sign_cert(const char *csr, const char *cacert, const char *cakey, const char *cert, unsigned long valid)  { -    FILE *stream;                           /* Flux ouvert en écriture     */ +    FILE *stream;                           /* Flux ouvert en lecture      */      X509_REQ *req;                          /* Certificat X509 à signer    */      EVP_PKEY *pk;                           /* Enveloppe pour clef publique*/      X509 *ca_cert;                          /* Certificat de l'autorité    */      EVP_PKEY *ca_pk;                        /* Enveloppe pour clef privée  */      X509 *x509;                             /* Certificat X509 à définir   */      int ret;                                /* Bilan d'un appel            */ -    X509_NAME *name;                        /* Désignation du certificat   */ +    X509_NAME *subject;                     /* Sujet de certificat         */      /* Chargement de la requête */ @@ -696,14 +779,14 @@ bool sign_cert(const char *csr, const char *cacert, const char *cakey, const cha      ret = X509_set_pubkey(x509, pk);      if (ret != 1) goto signing_failed; -    name = X509_REQ_get_subject_name(req); +    subject = X509_REQ_get_subject_name(req); -    ret = X509_set_subject_name(x509, name); +    ret = X509_set_subject_name(x509, subject);      if (ret != 1) goto signing_failed; -    name = X509_get_subject_name(ca_cert); +    subject = X509_get_subject_name(ca_cert); -    ret = X509_set_issuer_name(x509, name); +    ret = X509_set_issuer_name(x509, subject);      if (ret != 1) goto signing_failed;      /* Extensions */ diff --git a/src/analysis/db/certs.h b/src/analysis/db/certs.h index 132cd7f..50c96c0 100644 --- a/src/analysis/db/certs.h +++ b/src/analysis/db/certs.h @@ -54,6 +54,9 @@ bool build_keys_and_ca(const char *, const char *, unsigned long, const x509_ent  /* Crée un certificat pour application. */  bool build_keys_and_request(const char *, const char *, const x509_entries *); +/* Recharge l'identité inscrite dans une requête de signature. */ +bool load_identity_from_request(const char *, x509_entries *); +  /* Signe un certificat pour application. */  bool sign_cert(const char *, const char *, const char *, const char *, unsigned long); diff --git a/src/gui/dialogs/identity.c b/src/gui/dialogs/identity.c index 625c556..eae1069 100644 --- a/src/gui/dialogs/identity.c +++ b/src/gui/dialogs/identity.c @@ -24,19 +24,22 @@  #include "identity.h" +#include <malloc.h>  #include <string.h>  #include <i18n.h> +#include "../../analysis/db/auth.h"  #include "../../analysis/db/certs.h" +#include "../../common/extstr.h"  #include "../../core/logs.h"  /* Applique la nouvelle définition d'identité. */ -static void update_identity(GtkButton *button, GtkBuilder *); +static void update_identity(GtkButton *, GtkBuilder *); @@ -57,8 +60,11 @@ GtkWidget *create_identity_dialog(GtkWindow *parent, GtkBuilder **outb)  {      GtkWidget *result;                      /* Fenêtre à renvoyer          */      GtkBuilder *builder;                    /* Constructeur utilisé        */ -    x509_entries entries;                   /* Eléments identitaires       */ +    char *username;                         /* Nom par défaut              */      GtkEntry *entry;                        /* Zone de saisie à initialiser*/ +    char *filename;                         /* Fichier devant être présent */ +    x509_entries identity;                  /* Eléments identitaires       */ +    bool status;                            /* Bilan d'un chargement       */      builder = gtk_builder_new_from_resource("/org/chrysalide/gui/dialogs/identity.ui");      *outb = builder; @@ -67,47 +73,64 @@ GtkWidget *create_identity_dialog(GtkWindow *parent, GtkBuilder **outb)      gtk_window_set_transient_for(GTK_WINDOW(result), parent); -    /* Mise à jour de l'interface */ +    username = get_default_username(); -    memset(&entries, 0, sizeof(entries)); -    //load_identity(true, &entries); +    entry = GTK_ENTRY(gtk_builder_get_object(builder, "cn")); +    gtk_entry_set_placeholder_text(entry, username); -    if (entries.country != NULL) -    { -        entry = GTK_ENTRY(gtk_builder_get_object(builder, "c")); -        gtk_entry_set_text(entry, entries.country); -    } +    free(username); -    if (entries.state != NULL) -    { -        entry = GTK_ENTRY(gtk_builder_get_object(builder, "st")); -        gtk_entry_set_text(entry, entries.state); -    } +    /* Mise à jour de l'interface */ -    if (entries.locality != NULL) -    { -        entry = GTK_ENTRY(gtk_builder_get_object(builder, "l")); -        gtk_entry_set_text(entry, entries.locality); -    } +    filename = get_db_working_directory("clients", NULL, NULL, NULL); +    filename = stradd(filename, "client-csr.pem"); -    if (entries.organisation != NULL) -    { -        entry = GTK_ENTRY(gtk_builder_get_object(builder, "o")); -        gtk_entry_set_text(entry, entries.organisation); -    } +    status = load_identity_from_request(filename, &identity); -    if (entries.organisational_unit != NULL) -    { -        entry = GTK_ENTRY(gtk_builder_get_object(builder, "ou")); -        gtk_entry_set_text(entry, entries.organisational_unit); -    } +    free(filename); -    if (entries.country != NULL) +    if (status)      { -        entry = GTK_ENTRY(gtk_builder_get_object(builder, "cn")); -        gtk_entry_set_text(entry, entries.common_name); - -        gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1); +        if (identity.country != NULL) +        { +            entry = GTK_ENTRY(gtk_builder_get_object(builder, "c")); +            gtk_entry_set_text(entry, identity.country); +        } + +        if (identity.state != NULL) +        { +            entry = GTK_ENTRY(gtk_builder_get_object(builder, "st")); +            gtk_entry_set_text(entry, identity.state); +        } + +        if (identity.locality != NULL) +        { +            entry = GTK_ENTRY(gtk_builder_get_object(builder, "l")); +            gtk_entry_set_text(entry, identity.locality); +        } + +        if (identity.organisation != NULL) +        { +            entry = GTK_ENTRY(gtk_builder_get_object(builder, "o")); +            gtk_entry_set_text(entry, identity.organisation); +        } + +        if (identity.organisational_unit != NULL) +        { +            entry = GTK_ENTRY(gtk_builder_get_object(builder, "ou")); +            gtk_entry_set_text(entry, identity.organisational_unit); +        } + +        if (identity.common_name != NULL) +        { +            entry = GTK_ENTRY(gtk_builder_get_object(builder, "cn")); +            gtk_entry_set_text(entry, identity.common_name); + +            gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1); + +        } + +        free_x509_entries(&identity);      } @@ -141,7 +164,7 @@ static void update_identity(GtkButton *button, GtkBuilder *builder)  {      GtkEntry *entry;                        /* Zone de saisie à consulter  */      const gchar *data;                      /* Données internes à GTK      */ -    x509_entries entries;                   /* Nouvelle identité à pousser */ +    x509_entries identity;                  /* Nouvelle identité à pousser */      bool status;                            /* Bilan de la mise à jour     */      /* Récupération des éléments */ @@ -149,42 +172,42 @@ static void update_identity(GtkButton *button, GtkBuilder *builder)      entry = GTK_ENTRY(gtk_builder_get_object(builder, "c"));      data = gtk_entry_get_text(entry); -    entries.country = (strlen(data) > 0 ? strdup(data) : NULL); +    identity.country = (strlen(data) > 0 ? strdup(data) : NULL);      entry = GTK_ENTRY(gtk_builder_get_object(builder, "st"));      data = gtk_entry_get_text(entry); -    entries.state = (strlen(data) > 0 ? strdup(data) : NULL); +    identity.state = (strlen(data) > 0 ? strdup(data) : NULL);      entry = GTK_ENTRY(gtk_builder_get_object(builder, "l"));      data = gtk_entry_get_text(entry); -    entries.locality = (strlen(data) > 0 ? strdup(data) : NULL); +    identity.locality = (strlen(data) > 0 ? strdup(data) : NULL);      entry = GTK_ENTRY(gtk_builder_get_object(builder, "o"));      data = gtk_entry_get_text(entry); -    entries.organisation = (strlen(data) > 0 ? strdup(data) : NULL); +    identity.organisation = (strlen(data) > 0 ? strdup(data) : NULL);      entry = GTK_ENTRY(gtk_builder_get_object(builder, "ou"));      data = gtk_entry_get_text(entry); -    entries.organisational_unit = (strlen(data) > 0 ? strdup(data) : NULL); +    identity.organisational_unit = (strlen(data) > 0 ? strdup(data) : NULL);      entry = GTK_ENTRY(gtk_builder_get_object(builder, "cn"));      data = gtk_entry_get_text(entry); -    entries.common_name = (strlen(data) > 0 ? strdup(data) : NULL); +    identity.common_name = (strlen(data) > 0 ? strdup(data) : NULL);      /* Application de la nouvelle définition */      status = false;//register_standalone_certs(&entries); -    free_x509_entries(&entries); +    free_x509_entries(&identity);      if (status)          log_simple_message(LMT_INFO, _("New identity has been loaded with success!"));      else -        log_simple_message(LMT_ERROR, _("Failure while loading the new identity...")); +        log_simple_message(LMT_ERROR, _("Failure while reloading the new identity..."));  } diff --git a/src/gui/dialogs/identity.ui b/src/gui/dialogs/identity.ui index 25d398f..413d7f6 100644 --- a/src/gui/dialogs/identity.ui +++ b/src/gui/dialogs/identity.ui @@ -1,5 +1,5 @@  <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.21.0 --> +<!-- Generated with glade 3.22.1 -->  <interface>    <requires lib="gtk+" version="3.12"/>    <object class="GtkDialog" id="window"> @@ -8,8 +8,12 @@      <property name="title" translatable="yes">Identity</property>      <property name="modal">True</property>      <property name="window_position">center-on-parent</property> -    <property name="default_width">515</property> +    <property name="default_width">520</property> +    <property name="default_height">550</property>      <property name="type_hint">dialog</property> +    <child> +      <placeholder/> +    </child>      <child internal-child="vbox">        <object class="GtkBox" id="dialog-vbox1">          <property name="can_focus">False</property> @@ -78,7 +82,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">1</property> +                <property name="top_attach">2</property>                  <property name="width">2</property>                </packing>              </child> @@ -87,9 +91,7 @@                  <property name="width_request">500</property>                  <property name="visible">True</property>                  <property name="can_focus">False</property> -                <property name="label" translatable="yes">All the following information is used to create your authentication certifcate. This certificate grants you access to database servers and identifies each analysis change. - -<b>Warning: </b> updating this information drives to new signing requests for remote servers!</property> +                <property name="label" translatable="yes">All the following information is used to create your authentication certifcates. These certificates grant you access to database servers and identify each analysis change.</property>                  <property name="use_markup">True</property>                  <property name="wrap">True</property>                  <property name="xalign">0</property> @@ -109,7 +111,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">2</property> +                <property name="top_attach">3</property>                </packing>              </child>              <child> @@ -122,7 +124,7 @@                </object>                <packing>                  <property name="left_attach">1</property> -                <property name="top_attach">2</property> +                <property name="top_attach">3</property>                </packing>              </child>              <child> @@ -134,7 +136,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">3</property> +                <property name="top_attach">4</property>                  <property name="width">2</property>                </packing>              </child> @@ -147,7 +149,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">4</property> +                <property name="top_attach">5</property>                </packing>              </child>              <child> @@ -157,7 +159,7 @@                </object>                <packing>                  <property name="left_attach">1</property> -                <property name="top_attach">4</property> +                <property name="top_attach">5</property>                </packing>              </child>              <child> @@ -167,7 +169,7 @@                </object>                <packing>                  <property name="left_attach">1</property> -                <property name="top_attach">5</property> +                <property name="top_attach">6</property>                </packing>              </child>              <child> @@ -179,7 +181,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">5</property> +                <property name="top_attach">6</property>                </packing>              </child>              <child> @@ -191,7 +193,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">6</property> +                <property name="top_attach">7</property>                  <property name="width">2</property>                </packing>              </child> @@ -204,7 +206,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">7</property> +                <property name="top_attach">8</property>                </packing>              </child>              <child> @@ -214,7 +216,7 @@                </object>                <packing>                  <property name="left_attach">1</property> -                <property name="top_attach">7</property> +                <property name="top_attach">8</property>                </packing>              </child>              <child> @@ -224,7 +226,7 @@                </object>                <packing>                  <property name="left_attach">1</property> -                <property name="top_attach">8</property> +                <property name="top_attach">9</property>                </packing>              </child>              <child> @@ -236,7 +238,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">8</property> +                <property name="top_attach">9</property>                </packing>              </child>              <child> @@ -248,7 +250,7 @@                </object>                <packing>                  <property name="left_attach">0</property> -                <property name="top_attach">9</property> +                <property name="top_attach">10</property>                </packing>              </child>              <child> @@ -258,7 +260,81 @@                </object>                <packing>                  <property name="left_attach">1</property> -                <property name="top_attach">9</property> +                <property name="top_attach">10</property> +              </packing> +            </child> +            <child> +              <object class="GtkFrame"> +                <property name="visible">True</property> +                <property name="can_focus">False</property> +                <property name="label_xalign">0</property> +                <property name="shadow_type">none</property> +                <child> +                  <object class="GtkAlignment"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="left_padding">12</property> +                    <child> +                      <object class="GtkLabel"> +                        <property name="visible">True</property> +                        <property name="can_focus">False</property> +                        <property name="label" translatable="yes">Updating this information drives to new signing requests! Please contact the administrators of all the remote servers to update your accesses. + +The authorization for the internal server is updated automatically.</property> +                        <property name="wrap">True</property> +                      </object> +                    </child> +                  </object> +                </child> +                <child type="label"> +                  <object class="GtkLabel"> +                    <property name="visible">True</property> +                    <property name="can_focus">False</property> +                    <property name="label" translatable="yes">Warning</property> +                    <attributes> +                      <attribute name="weight" value="bold"/> +                    </attributes> +                  </object> +                </child> +              </object> +              <packing> +                <property name="left_attach">0</property> +                <property name="top_attach">1</property> +                <property name="width">2</property> +              </packing> +            </child> +            <child> +              <object class="GtkSeparator" id="separator2"> +                <property name="visible">True</property> +                <property name="can_focus">False</property> +              </object> +              <packing> +                <property name="left_attach">0</property> +                <property name="top_attach">11</property> +                <property name="width">2</property> +              </packing> +            </child> +            <child> +              <object class="GtkLabel"> +                <property name="visible">True</property> +                <property name="can_focus">False</property> +                <property name="label" translatable="yes">Certificate validity period (in seconds):</property> +                <property name="xalign">1</property> +              </object> +              <packing> +                <property name="left_attach">0</property> +                <property name="top_attach">12</property> +              </packing> +            </child> +            <child> +              <object class="GtkEntry"> +                <property name="visible">True</property> +                <property name="can_focus">True</property> +                <property name="placeholder_text" translatable="yes">94608000</property> +              </object> +              <packing> +                <property name="left_attach">1</property> +                <property name="top_attach">12</property>                </packing>              </child>            </object> @@ -274,8 +350,5 @@        <action-widget response="-6">button1</action-widget>        <action-widget response="-10">button2</action-widget>      </action-widgets> -    <child> -      <placeholder/> -    </child>    </object>  </interface> | 
