MySQL UDF: fopen = разрешение запрещено - PullRequest
2 голосов
/ 26 мая 2010

РЕДАКТИРОВАТЬ : я переписал этот вопрос, так как не получил ответа и сейчас пытаюсь сузить проблему.

Я пытаюсь создать функцию mysql UDF , проверяющую, существует ли файл на стороне сервера. Эта функция вызывает «открыть / закрыть». Он не работает, даже если файл доступен для чтения.

Я поставил код этой функции ниже:

#include <mysql.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

/* The initialization function */
my_bool fileExists_init(
        UDF_INIT *initid,
        UDF_ARGS *args,
        char *message
        )
  {
  /* check the args */
  if (!(args->arg_count == 1 &&
        args->arg_type[0] == STRING_RESULT
        ))
    {
    strncpy(message,"Bad parameter expected a string",MYSQL_ERRMSG_SIZE);
    return 1;
    }
  initid->maybe_null=1;
  initid->ptr= NULL;
  return 0;
  }

/* The deinitialization function */
void  fileExists_deinit(UDF_INIT *initid)
    {
    }

#define MAX_RESULT_LENGTH 250
char *fileExists(
    UDF_INIT *initid, UDF_ARGS *args, char *result,
    unsigned long *length, char *is_null, char *error)
 {
 //bad filename
 if(args->args[0]==NULL  || args->lengths[0]==0 || args->lengths[0] >= FILENAME_MAX )
    {
    strncpy(result,"#BAD_INPUT",MAX_RESULT_LENGTH);
    }
  else
    {
          char  filename[FILENAME_MAX+1];
      int err;
      int in;
      //create a NULL terminated string
      memcpy(filename,args->args[0],args->lengths[0]);
      filename[args->lengths[0]]=0;
      errno=0;
      in=open(filename,O_RDONLY|O_NDELAY);
      err=errno;
      if(in<0)
        {
        snprintf(result,MAX_RESULT_LENGTH,"#ERR:\"%s\":\"%s\".",strerror(err),filename);    
        }
      else
        {
        close(in);
        snprintf(result,MAX_RESULT_LENGTH,"OK:\"%s\".",filename);   
        }
    }
  *length=strlen(result);
  return result;
  }

Марка:

gcc -Wall -DMYSQL_VERSION -fPIC -shared `mysql_config --cflags` -o `mysql_config --plugindir`/libfileexists.so udffileexists.c  `mysql_config --libs `

Тест:

хорошо, mysql может открывать некоторые файлы:

mysql>  create function fileExists RETURNS STRING SONAME 'libfileexists.so'; select fileExists("/etc/mysql/my.cnf"); drop function fileExists;
Query OK, 0 rows affected (0.00 sec)

+---------------------------------+
| fileExists("/etc/mysql/my.cnf") |
+---------------------------------+
| OK:"/etc/mysql/my.cnf".         | 
+---------------------------------+
1 row in set (0.00 sec)



mysql>  create function fileExists RETURNS STRING SONAME 'libfileexists.so'; select fileExists("/tmp/file.txt"); drop function fileExists;
Query OK, 0 rows affected (0.00 sec)

+-------------------------------+
| fileExists("/tmp/file.txt")   |
+-------------------------------+
| OK:"/tmp/file.txt".           | 
+-------------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

ОК, нет проблем, это работает, я могу открыть () file.txt в / tmp /

ls -la /tmp 
drwxrwxrwt 16 root    root       4096 2010-05-28 15:45 .
-rw-r--r--  1 lindenb lindenb       0 2010-05-28 15:25 file.txt

Но когда я хочу проверить файл в / data :

ls -la /data
drwxrwxrwx  4 root    root        4096 2010-05-28 16:11 .
-rw-r--r--  1 lindenb lindenb        0 2010-05-28 15:25 file.txt

Я получил:

mysql>  create function fileExists RETURNS STRING SONAME 'libfileexists.so'; select fileExists("/data/file.txt"); drop function fileExists;
Query OK, 0 rows affected (0.00 sec)

+--------------------------------------------+
| fileExists("/data/file.txt")               |
+--------------------------------------------+
| #ERR:"Permission denied":"/data/file.txt". | 
+--------------------------------------------+
1 row in set (0.00 sec)

Есть идеи?

Спасибо!

Ответы [ 2 ]

3 голосов
/ 01 июня 2010

mysqld был защищен apparmor .

AppArmor представляет один из нескольких возможные подходы к проблеме ограничение действий, которые установлены Программное обеспечение может взять.

Я добавил

/data/** r,

в конце

/etc/apparmor.d/usr.sbin.mysqld

аппарат был перезапущен:

/etc/init.d/apparmor restart

и теперь мой UDF работает отлично! : -)

0 голосов
/ 31 мая 2010

Почему вы используете открытый файл? Возможно, лучше сделать это так:

char *fileExists(
    UDF_INIT *initid, UDF_ARGS *args, char *result,
    unsigned long *length, char *is_null, char *error)
{
 //bad filename
 if(args->args[0]==NULL  || args->lengths[0]==0 || args->lengths[0] >= FILENAME_MAX )
 {
   strncpy(result,"#BAD_INPUT",MAX_RESULT_LENGTH);
 }
 else
 {
   char  filename[FILENAME_MAX+1];
   int err;
   int in;
   struct stat statbuffer;
   //create a NULL terminated string
   memcpy(filename,args->args[0],args->lengths[0]);
   filename[args->lengths[0]]=0;
   errno=0;
   if (!stat(filename, &statbuffer)){
     if (S_ISREG(statbuffer.st_mode)){
        snprintf(result,MAX_RESULT_LENGTH,"OK:\"%s\".",filename);
     }else{
        snprintf(result,MAX_RESULT_LENGTH,"#ERR:\"%s\":\"%s\".",strerror(err),filename);
     }
   }else{
     snprintf(result,MAX_RESULT_LENGTH,"#ERR:\"%s\":\"%s\".",strerror(err),filename);
   }
 }
 *length=strlen(result);
 return result;
}

Вместо открытия файла используйте stat , это будет надежный способ проверить, существует ли файл, а также будет проще понять, почему именно stat сбой функции.

...