, , Appel d’API en CL

Nous utilisons de plus en plus les services SQL pour de nombreuses actions : accès aux *DTAQ, *DTAARA, travaux etc …

Par exemple, pour accéder au contenu d’une variable d’environnement, la vue QSYS2.ENVIRONMENT_VARIABLE_INFO est très simple à utiliser :

Dans un programme RPG, il est très simple d’effectuer une lecture SQL.

Mais dans certains cas, nous préférerons utiliser les APIs système : pour la performance, ou dans le CL ! En CL, il est possible d’exécuter une instruction SQL, mais pas de récupérer un result sets (en tout cas pas simplement et avec une bonne performance).

L’appel d’API depuis le CL ne pose pas de soucis, principalement depuis les évolutions permettant de maitriser l’allocation mémoire des variables (variables autonomes, basées sur un pointeur, ou basée sur une autre variable – équivalent OVERLAY du RPG) :

Maintenant, lorsque l’on utilise des API, il est (souvent) nécessaire de passer par des pointeurs, de façon explicite ou non. Par exemple, c’est le cas pour QUSRJOBI même si l’on a pas déclaré de pointeur dans notre programme CL :

En réalité, lors d’un appel de programme ou procédure, les paramètres sont transmis par défaut par référence : concrètement on passe un pointeur sur le début de la valeur, mais pas la valeur elle-même !

Il faut commencer à interpréter les prototypes des API en fonction du langage d’appel …

Le système étant écrit en C, certaines API utilisent la définition C d’une chaine de caractères : un pointeur sur le premier caractère, la fin de la chaîne étant marquée par le premier octet null !

En RPG, nous avons la fonction %str() qui permet de gérer ceci :

En CL, pas de fonction équivalent pour gérer cela.

Prenons par exemple l’API getEnv() (en fait une fonction de la bibliothèque standard C) :

Il faut fournir en entrée le nom de la variable d’environnement, au format C String, c’est à dire à terminaison nulle.

De même, la valeur de retour est un pointeur sur le début de la valeur. La fin se situe au premier octet null rencontré …

Voici un exemple d’appel :

Nous déclarons simplement une variable de type CHAR(1) initialisée à x’00’ :

DCL VAR(&SPC_INIT) TYPE(*CHAR) LEN(1) VALUE(X'00')

Cela nous sert à créer la valeur pour l’appel : chaine à terminaison nulle contenant le nom de la variable d’environnement recherchée (ici CLASSPATH) :

CHGVAR &ENVVAR ( 'CLASSPATH' *CAT &SPC_INIT )

Pour décoder la valeur de retour, il nous faut parcourir la valeur reçue jusqu’à trouver la terminaison nulle. On utilise simplement %SCAN pour trouver la position et redécouper :

CHGVAR VAR(&POSNULL) VALUE(%SCAN(&SPC_INIT &ENVVARVAL) - 1 )
CHGVAR &FINALVAL %SUBSTRING(&ENVVARVAL 1 &POSNULL)

Au final, très peu de code à ajouter, mais nécessite une compréhension de la documentation des APIs, des types de données dans les différents langages, et des mécanismes de transmission de paramètres !


, La valeur de sécurité QSECURITY

La valeur de sécurité QSECURITY

La valeur QSECURITY permet de connaître le niveau de sécurité appliqué au système.

Il y a 5 niveaux de sécurité, 10 – 20 – 30 – 40 – 50.

10 étant la sécurité la plus faible et 50 la plus élevé.

Pour connaître la valeur du niveau de sécurité de votre système, vous devez vous rendre dans les valeurs système en utilisant la commande WRKSYSVAL.

Au vu du nombre de valeurs de notre système, on va trier par sous-ensemble.

On va rentrer *SEC pour aller voir les valeurs système de sécurité.

On affiche ensuite la valeur système QSECURITY.

Sur la ligne rouge on peut voir le niveau de sécurité de notre système.

Dans le carré bleu, on peut voir les 5 niveaux de sécurité avec une courte description.

Depuis la version V7R5, le niveau de sécurité minimal est de 30.

Tableau des valeurs de QSECURITY depuis la V7R5

IBM recommande le niveau de sécurité 40 en raison des vulnérabilités trouvées au niveau 30.

La plupart des entreprises possédant un IBM i travaillent avec un niveau de sécurité 40.

Seuls les services financiers et quelques autres entreprises utilisent le niveau de sécurité 50 pour se conformer aux normes de défense américaine.

Voyons maintenant en détails, les 5 niveaux de sécurité :

Niveau 10 Pas de mot de passe requis, des profils sont créés à chaque fois qu’un utilisateur essaie de se connecter. Les utilisateurs créés ont accès à tout car l’autorité *ALLOBJ leur est attribuée automatiquement. Ce niveau n’est plus entretenu par IBM.

Niveau 20 → À ce niveau l’autorité *ALLOBJ est toujours attribuée à chaque utilisateur. En plus du niveau 10, un identifiant et un mot de passe sont nécessaires pour se connecter. Seul un profil *SECADM peut créer des nouveaux profils utilisateur. Ce niveau n’est plus admis depuis la V7R5.

Niveau 30 → En plus du niveau 20, ce niveau peut gérer les autorisations des utilisateurs au cas par cas. Les profils ayant l’autorité *ALLOBJ sont forcément créés avec la classe de sécurité *SECOFR, les autres n’ont pas cette autorité.

Niveau 40 → Protection de l’intégrité du système d’exploitation. Signature et sécurité des ressources. Le système empêche les tentatives d’appeler directement des programmes système non reconnus.

Niveau 50 → Protection renforcée de l’intégrité du système d’exploitation. Signature et sécurité des ressources. Avant de passer à ce niveau, la mise en place du journal d’audit est obligatoire. Ce niveau a été créé pour répondre à la norme C2 (Norme de département de défense Américain). Une meilleure protection des blocs de contrôle interne est appliquée.

, , Droits et génération SQL script

Vous devez moderniser votre base de données, pour cela vous pouvez commencer par extraire le source de votre PF,
par exemple en passant par Générations d’instructions SQL dans ACS , ou en utilisant la procédure SQL de QSYS2 GENERATE_SQL Ou GENERATE_SQL_OBJECT ,


La plus part du temps on obtient un scripte SQL qui vous permettra de générer votre nouvelle table , ici un exemple ou on a enlevé les commentaires.

Que ce passe t’il au niveau des droits ?

Avant par DSPOBJAUT

par DROITS dans ACS

La liste d’autorisations

Premier effet vous pouvez avoir des différences sur les droits publics

exemple ici

Après

Vous vous retrouvez avec un droit USER DEF au lieu de *CHANGE et vous avez perdu le droit exécute, on est d’accord ca ne change rien sur une table, c’est juste un peu moins lisible quand on analyse au niveau du système

le plus gênant c’est la liste d’autorisation que vous perdez
et la cela peux changer complètement puisque vous perdez 1 voir 2 niveaux de recherches

Dans notre cas FORM06 se retrouve avec des droits *PUBLIC

Conclusion :


Après avoir modernisé vos tables, vous devez réappliquer vos droits le plus simple est de généré un objet de référence

une autre solution est de vous affranchir des listes d’autorisation qui ne sont pas générées dans SQL

, , , Tuez les jobs SSH dans QINTER

Si vous commencez à faire du SSH (en tant que client), par exemple pour faire du GitHub, vous avez des jobs qui vont rester et que vous devrez tuer par un kill ou un ENDJOB.

C’est des jobs BCI qui restent après avoir arrêté vos JOBs interactifs.

Voici un petit script CLP qui permet de faire ça, il vous suffit de le planifier tous les soirs à 23 heures par exemples.

Ici on a utiliser la fonction table QSYS2.ACTIVE_JOB_INFO et la fonction QSYS2.QCMDEXC et on packagé le tout dans un CLP …

PGM
/* Suppression des jobs SSH dans QINTER */
dcl &NBRCURRCD *dec 10
/*  Exécution de la requete SQL */
             RUNSQL     SQL('Create table qtemp/sortie as(SELECT +
                          QSYS2.QCMDEXC(''ENDJOB '' CONCAT +
                          JOB_NAME)  as resultat FROM +
                          TABLE(QSYS2.ACTIVE_JOB_INFO(SUBSYSTEM_LIST_+
                          FILTER => ''QINTER'')) X  where job_type +
                          = ''BCI'') with data') COMMIT(*NONE)
             MONMSG     MSGID(SQL0000) exec(do)
             SNDUSRMSG  MSG('Erreur dans l''exécution de la requête +
                          SQL d''épuration des jobs SSH') +
                          MSGTYPE(*INFO)
             Return
             enddo
  /* Envoi d'un message de fin */
             RTVMBRD    FILE(QTEMP/SORTIE) NBRCURRCD(&NBRCURRCD)
             if cond(&NBRCURRCD > 0) then(do)
             SNDUSRMSG  MSG(%CHAR(&NBRCURRCD) *TCAT ', job(s) SSH +
                          arrêté(s)') MSGTYPE(*INFO)
             enddo
             else do
             SNDUSRMSG  MSG('Pas de Job SSH à Supprimer ') +
                          MSGTYPE(*INFO)
             enddo
ENDPGM

Sur les job de ssh-agent vous pouvez demander le kill directement comme ceci, merci à Julien …

La commande QSH lancer par votre CL qui vous permet de soumettre se présente donc comme ça :

eval "$(ssh-agent -s)" ; // Démarrage de l'agent 
SSH ssh-add /home/jl/.ssh/github ; // Ajout de la clé à l'agent 
ssh -T git@github.com ; // Test de connexion à GitHub 
ssh-agent -k // Arrêter l'agent
, , Visual studio code IBM i Snippets

Vous connaissez tous, au moins de nom l’extension « code for i » qui vous permet d’éditer vos sources RPGLE dans votre éditeur favori qui est publié par notre Ami Liam Allan

Si voulez en savoir plus une vidéo très bien faite de notre ami de Yvon est disponible sur la chaine youtube de Volubis ici

Mais il existe également des extensions créé par d’autres contributeurs en voici une qui est apparu en 2022 « IBM i Snippets », elle a été créée par Andy Youens.

L’installation est très simple à partir de la gestion des extensions

Le principe de cette extension est de vous proposer des exemples de codes (par exemple des squelettes pour du RPGLE ou CLLE).

Son usage est très simple vous devez saisir « !i » dans votre éditeur favori .


Cette extension bouge beaucoup depuis sa sortie et les dernières contributions sont récentes, n’hésitez pas à proposer des exemples de codes si vous en avez qui soit présentable

Nous pensons qu’il y aura de plus en plus de extensions disponibles pour l’IBMI et une amélioration de celle exitantes extensions existantes, il est donc important d’avoir un œil ce mode de développement , en sachant que les « JEUNNNNES » connaissent déjà cet interface

Les annonces de la TR1 de la 7.5 ou TR7 de la 7.4 sont sorties et disponibles ici https://www.ibm.com/support/pages/node/1119129/


• Voici selon nous 5 nouveautés à suivre dans cette Technology Refresh

• 1) La possibilité de faire des mises à jour sur des flux json avec la fonction JSON_UPDATE , ça fait longtemps que nos équipes râlaient, parce qu’elles devaient faire du bricolage quand on travaillait sur du flux json.


• 2) La possibilité d’exécuter des fonctions table remote, par exemple avec le service REMOTE TABLE, un object_statistics sur une partition distante. Ça peut avoir du sens pour automatiser des contrôles de cohérence.


• 3) Les nouvelles fonctions table, SYSTOOLS.AUDIT_JOURNAL_xx qui permettent de traiter les postes d’audit et plus globalement les nouveautés sur les audits comme la disponibilité d’IDS dans Navigator for i qui n’était pas présent dans la nouvelle interface.


• 4) SELF (SQL Error Logging Facility) qui va permettre de mettre au point les traitements SQL en attrapant de manière plus fine les erreurs et en pouvant les suivre dans le temps sans passer par un mode de debug parfois trop bavard en log.


• 5) Les nouveaux services pour administrer Object Connect (vous savez les commandes SAVRSTxxx, CHANGE_OBJECTCONNECT et OBJECTCONNECT_INFO), un petit rappel, Object Connect peut désormais fonctionner en IP. Disponible par PTF et c’est la dernière fonction SNA qui n’avait pas d’équivalent ip. Ces nouveaux services permettront d’administrer et d’avoir des informations sur ce qui s’exécute dans les échanges inter-machines.


• Rendez-vous en décembre pour les premiers tests.

, , , Date source de vos programmes

On est amené quand on fait des analyses à regarder les dates de source, on constate que ces dates sont à null pour tous les objets de type ILE.

Vous avez une vue QSYS2.PROGRAM_INFO qui permet d’avoir ces informations sur les programmes, un peu comme la commande DSPPGM.

Voici pourquoi : quand vous travaillez en OPM vous compilez des sources qui deviennent des programmes; quand vous travaillez en ILE, vous compilez des sources qui deviennent des modules, puis vous les assemblez pour créer des programmes et du coup une date de source sur un programme ILE ne veut rien dire.

En réalité un programme a un module qui s’appelle point d’entrée programme qui, quand on travaille en BND (CRTBND*), est le seul module placé dans qtemp qui est assemblé pour créer votre programme.

On voit donc que si on veut, on peut assimiler la date du source du programme à la date du module PEP, qui dans plus de 99 % des cas a le même nom que le programme.
On a une deuxième vue permet d’avoir les modules par programme, QSYS2.BOUND_MODULE_INFO.

Il faudra donc combiner les 2 vues.

par exemple :

  • Pour les programmes ILE

SELECT a.PROGRAM_NAME, a.PROGRAM_TYPE, b.SOURCE_FILE_LIBRARY, b.SOURCE_FILE,
b.SOURCE_FILE_MEMBER, b.SOURCE_CHANGE_TIMESTAMP
FROM QSYS2.PROGRAM_INFO A join QSYS2.BOUND_MODULE_INFO B
on a.PROGRAM_NAME = b.PROGRAM_NAME
and A.PROGRAM_NAME = b.BOUND_MODULE and A.PROGRAM_LIBRARY = b.PROGRAM_LIBRARY
WHERE a.PROGRAM_LIBRARY = ‘FADY’ and a.PROGRAM_TYPE = ‘ILE’

  • Pour les programmes OPM

SELECT a.PROGRAM_NAME, a.PROGRAM_TYPE, A.SOURCE_FILE_LIBRARY, A.SOURCE_FILE, A.SOURCE_FILE_MEMBER,
A.SOURCE_FILE_CHANGE_TIMESTAMP
FROM QSYS2.PROGRAM_INFO A
WHERE a.PROGRAM_LIBRARY = ‘FADY’ and a.PROGRAM_TYPE = ‘OPM’

en faisant l’union des deux requêtes vous aurez les dates de tous vos programmes ILE et OPM.

Il y a sans doute d’autres solutions mais celle-ci est très simple à utiliser.

, , Droits SQL sur les Zones

On m’a récemment demandé comment savoir si un fichier était couvert par des droits SQL sur les zones

J’ai d’abord pensé que la fonction table QSYS2.OBJECT_PRIVILEGES allait me rendre ce service !

donc j’ai lancé cette requête pour analyser mon fichier

Exemple :

SELECT *
FROM TABLE(QSYS2.OBJECT_PRIVILEGES(‘MABASESQL’, ‘CLIENTS’, ‘*FILE’));

et je n’ai pas trouvé l’information dans les zones renvoyées

puis j’ai essayé avec les commandes historiques en sortie de fichier ici DSPOBJAUT

Exemple :

DSPOBJAUT OBJ(MABASESQL/CLIENTS)
OBJTYPE(FILE) OUTPUT(OUTFILE)
OUTFILE(MABASESQL/LSTAUT)

Select * from MABASESQL.lstaut

et la on a le résultat qui l’indique
ZONE OAOBJA à ‘USER DEF’ et une ZONE des DATA ici OAUPD à ‘/’

En résumé

On ne sait pas par SQL, mais on sait faire par une sortie fichier historique


Oui je sais , on peut trouver l’information par des vues spécifiques dans QSYS2 et SYSIBM

Vous avez d’abord la vue SYSIBM.SQLCOLPRIVILEGES mais attention, vous avez toutes les autorisations sur la zone y compris celles qui correspondent à un *CHANGE sur le fichier par exemple.


exemple :

Select * from SYSIBM.SQLCOLPRIVILEGES
where TABLE_SCHEM = ‘MABASESQL’ and TABLE_NAME = ‘CLIENTS’

order by column_name, grantee


Ou mieux la vue QSYS2.COLUMN_PRIVILEGES qui ne contient que les zones avec des autorisations spécifiques

exemple

Select * from QSYS2.COLUMN_PRIVILEGES
where TABLE_SCHEMA = ‘MABASESQL’ and TABLE_NAME = ‘CLIENTS’

j’ai donc fait une RFE pour avoir l’information dans la fonction table QSYS2.OBJECT_PRIVILEGES

Si vous êtes intéressés votez pour moi c’est ici https://2e4ccba981d63ef83a875dad7396c9a0.ideas.aha.io/ideas/RIRP-I-1260

Je vous indiquerais la réponse d’IBM sur le sujet