"BECOME USER" sous Linux

En faisant des recherches sur Oracle, je suis tombé sur un article très intéressant intitulé « CHANGE USER » OPI call. En substance, l’article pointe une API OCI non documentée pour changer d’utilisateur et propose un exemple sous Windows pour l’utiliser. Ne disposant malheureusement pas du système d’exploitation de la firme de Redmond, j’ai modifié le programme pour Linux; vous trouverez ci-dessous avec l’accord de l’auteur le code source:

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <dlfcn.h>

#include "oci.h"

typedef int (*UPICUI) (int, int, const char *, int);
typedef int (*KPUSVC2HST) (OCISvcCtx *, OCIError *, int *, int);

int main(int argc, char * argv[])
{
OCIEnv *myenvhp; /* the environment handle */
OCIServer *mysrvhp; /* the server handle */
OCIError *myerrhp; /* the error handle */
OCISession *myusrhp; /* user session handle */
OCISvcCtx *mysvchp; /* the service handle */
OCIStmt *stmt;
OCIDefine *dfn;
char buf[10240];
UPICUI upicui;
KPUSVC2HST kpusvc2hst;
int hst;
void *handle;

#define SID "BLACK"

assert (OCIEnvCreate (&myenvhp, OCI_THREADED|OCI_OBJECT, 0, 0, 0, 0, 0, 0)==0);

assert (OCIHandleAlloc (myenvhp, (dvoid**)&mysrvhp, OCI_HTYPE_SERVER, 0, 0)==0);

assert (OCIHandleAlloc (myenvhp, (dvoid**)&myerrhp, OCI_HTYPE_ERROR, 0, 0)==0);

assert (OCIServerAttach (mysrvhp, myerrhp, (const OraText *)SID, strlen (SID), OCI_DEFAULT)==0);

assert (OCIHandleAlloc (myenvhp, (dvoid**)&mysvchp, OCI_HTYPE_SVCCTX, 0, 0)==0);

assert (OCIAttrSet (mysvchp, OCI_HTYPE_SVCCTX, mysrvhp, 0, OCI_ATTR_SERVER, myerrhp)==0);

assert (OCIHandleAlloc (myenvhp, (dvoid**)&myusrhp, OCI_HTYPE_SESSION, 0, 0)==0);

assert (OCIHandleAlloc (myenvhp, (dvoid**)&stmt, OCI_HTYPE_STMT, 0, 0)==0);

#define USERNAME "sys"
#define PASSWORD "change_on_install"

assert (OCIAttrSet (myusrhp, OCI_HTYPE_SESSION, USERNAME, strlen(USERNAME), OCI_ATTR_USERNAME, myerrhp)==0);

assert (OCIAttrSet (myusrhp, OCI_HTYPE_SESSION, PASSWORD, strlen(PASSWORD), OCI_ATTR_PASSWORD, myerrhp)==0);

assert (OCISessionBegin (mysvchp, myerrhp, myusrhp, OCI_CRED_RDBMS, OCI_SYSDBA)==0);

handle = dlopen ("libclntsh.so", RTLD_LAZY);assert(handle!=NULL);

upicui=(UPICUI) dlsym(handle, "upicui"); assert (upicui!=NULL);

kpusvc2hst=(KPUSVC2HST) dlsym(handle, "kpusvc2hst");
assert (kpusvc2hst!=NULL);

printf ("kpusvc2hst -> %dn", (kpusvc2hst) (mysvchp, myerrhp, &hst, 1));

#define USERNAME2 "SCOTT"

printf ("upicui -> %dn", (upicui)( hst, 0, USERNAME2, strlen (USERNAME2) ));

assert (OCIAttrSet (mysvchp, OCI_HTYPE_SVCCTX, myusrhp, 0, OCI_ATTR_SESSION, myerrhp)==0);

#define STMT "select user from dual"

assert (OCIStmtPrepare (stmt, myerrhp, (const OraText *)STMT, strlen (STMT), OCI_NTV_SYNTAX, OCI_DEFAULT)==0);

assert (OCIDefineByPos (stmt, &dfn, myerrhp, 1, buf, 10240, SQLT_STR, 0, 0, 0, OCI_DEFAULT)==0);

assert (OCIStmtExecute (mysvchp, stmt, myerrhp, 1, 0, NULL, NULL, OCI_DEFAULT)==0);

printf ("%sn", buf);

dlclose(handle);
}

Pour l’utiliser, positionnez l’environnement oracle, y compris LD_LIBRARY_PATH, modifiez les valeurs de SID, USERNAME, PASSWORD et USERNAME2 dans le code et compilez le programme comme ci-dessous:

gcc -I$ORACLE_HOME/rdbms/public 
-L$ORACLE_HOME/lib -lclntsh
-o demo demo.c

Et voilà, vous pouvez tester le programme comme ci-dessous:

./demo

kpusvc2hst -> 0
upicui -> 0
SCOTT

Bon! Mais ça ne répond pas encore à ma question…

PS: Jetez un œil sur le post de Laurent intitulée su in sqlplus pour une méthode supportée… Celle-ci c’est pour ceux qui cherchent le petite bête.