#ifdef LINUX #include #include #include #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lua/lualib.h" // zip library #include "3rd/zip/zip.h" #define MAX_PATH_LEN 1024 /** * Trim a string by a character on both ends * @param str The target string * @param delim the delim */ static void trim(char* str, const char delim) { if(!str || strlen(str) == 0) return; char * p = str; int l = strlen(p); while(l > 0 && p[l - 1] == delim) p[--l] = 0; while(* p && (* p) == delim ) ++p, --l; memmove(str, p, l + 1); } static int l_check_login (lua_State *L) { #ifdef LINUX const char* username = luaL_checkstring(L,1); const char* password = luaL_checkstring(L,2); char *encrypted; struct passwd *pwd; struct spwd *spwd; /* Look up password and shadow password records for username */ pwd = getpwnam(username); if (pwd == NULL) { lua_pushboolean(L,0); lua_pushstring(L, strerror(errno)); return 2; } spwd = getspnam(username); /*if (spwd == NULL) { lua_pushboolean(L,0); printf("no permission to read shadow password file\n"); return 1; }*/ if (spwd != NULL) /* If there is a shadow password record */ { pwd->pw_passwd = spwd->sp_pwdp; /* Use the shadow password */ } /*else { lua_pushboolean(L,0); printf("shadow record is null \n" ); return 1; }*/ /* Encrypt password and erase cleartext version immediately */ encrypted = crypt(password, pwd->pw_passwd); if (encrypted == NULL) { lua_pushboolean(L,0); lua_pushstring(L, strerror(errno)); return 2; } if(strcmp(encrypted, pwd->pw_passwd) == 0) { lua_pushboolean(L,1); return 1; } else { lua_pushboolean(L,0); return 1; } #else // macos // just pass the check, for test only lua_pushboolean(L,0); lua_pushstring(L, "Login by shadow passwd is not supported on this system"); return 2; #endif } static void get_userId(const char* name, uid_t* uid,gid_t* gid ) { struct passwd *pwd; uid_t u; char *endptr; if (name == NULL || *name == '\0') { *uid = -1; *gid=-1; return; } u = strtol(name, &endptr, 10); if (*endptr == '\0') { *uid = u; *gid = -1; return; } pwd = getpwnam(name); if (pwd == NULL) { *uid = -1; *gid=-1; return; } *uid = pwd->pw_uid; *gid = pwd->pw_gid; } static int l_fork(lua_State* L) { int pid = fork(); lua_pushnumber(L, pid); return 1; } static int l_waitpid(lua_State* L) { int pid = luaL_checknumber(L,1); int nohang = luaL_checknumber(L,2); pid_t st; int status; if(nohang) { st = waitpid(pid, &status, WNOHANG); } else { st = waitpid(pid, &status, 0); } lua_pushnumber(L, st); return 1; } static int l_kill(lua_State* L) { int pid = luaL_checknumber(L,1); if(pid == -1) pid = getpid(); int status = kill(pid, SIGHUP); lua_pushnumber(L, status); return 1; } static int l_setuid(lua_State* L) { uid_t uid = (uid_t) luaL_checknumber(L,1); if((int)uid != -1) { if(setuid(uid) < 0) { lua_pushboolean(L,0); lua_pushstring(L, strerror(errno)); return 2; } else { //printf("UID set\n"); lua_pushboolean(L,1); return 1; } } else lua_pushboolean(L,0); return 1; } static int l_setgid(lua_State* L) { uid_t gid = (uid_t) luaL_checknumber(L,1); if((int)gid != -1) { if(setgid(gid) < 0) { lua_pushboolean(L,0); lua_pushstring(L, strerror(errno)); return 2; } else { //printf("GID set\n"); lua_pushboolean(L,1); return 1; } } else lua_pushboolean(L,0); return 1; } static int l_getuid(lua_State* L) { const char* name = luaL_checkstring(L,1); uid_t uid = -1; uid_t gid = -1; get_userId(name,&uid,&gid); lua_newtable(L); lua_pushstring(L,"id"); lua_pushnumber(L,uid); lua_settable(L,-3); lua_pushstring(L,"gid"); lua_pushnumber(L,gid); lua_settable(L,-3); int j, ngroups = 30; //only first 10 group gid_t *groups; struct group *gr; // find all the groups if((int)uid != -1 && (int)gid != -1) { /* Retrieve group list */ groups = malloc(ngroups * sizeof (gid_t)); if (groups == NULL) { return 1; } if (getgrouplist(name, gid, groups, &ngroups) == -1) { free(groups); return 1; } /* retrieved groups, along with group names */ lua_pushstring(L,"groups"); lua_newtable(L); for (j = 0; j < ngroups; j++) { gr = getgrgid(groups[j]); if (gr != NULL) { //printf("%d: (%s)\n", groups[j],gr->gr_name); lua_pushnumber(L, groups[j]); lua_pushstring(L, gr->gr_name); lua_settable(L,-3); } } lua_settable(L, -3); free(groups); } return 1; } static void timestr(time_t time, char* buf,int len,char* format, int gmt) { struct tm t; if(gmt) { gmtime_r(&time, &t); } else { localtime_r(&time, &t); } strftime(buf, len, format, &t); } static int l_file_stat(lua_State* L, const char* path) { //const char* path = luaL_checkstring(L,-1); //printf("PATH %s\n", path); //lua_pop(L,1); char date[64]; struct stat st; if( stat(path, &st) == 0 ) { // recore for file lua_newtable(L); //type lua_pushstring(L,"type"); if(S_ISDIR(st.st_mode)) lua_pushstring(L,"dir"); else lua_pushstring(L,"file"); lua_settable(L,-3); //ctime lua_pushstring(L,"ctime"); timestr(st.st_ctime,date,sizeof(date),"%a, %d %b %Y %H:%M:%S GMT",1); lua_pushstring(L,date); lua_settable(L,-3); //mtime lua_pushstring(L,"mtime"); timestr(st.st_mtime,date,sizeof(date),"%a, %d %b %Y %H:%M:%S GMT",1); lua_pushstring(L,date); lua_settable(L,-3); //size lua_pushstring(L,"size"); lua_pushnumber(L,st.st_size); lua_settable(L,-3); // uid lua_pushstring(L,"uid"); lua_pushnumber(L,st.st_uid); lua_settable(L,-3); // gid lua_pushstring(L,"gid"); lua_pushnumber(L,st.st_gid); lua_settable(L,-3); lua_pushstring(L,"permissions"); sprintf(date," (%3o)", st.st_mode&0777); lua_pushstring(L,date); lua_settable(L,-3); // permission lua_pushstring(L,"perm"); lua_newtable(L); lua_pushstring(L,"owner"); lua_newtable(L); lua_pushstring(L,"read"); lua_pushboolean(L, (st.st_mode & S_IRUSR)==0?0:1); lua_settable(L,-3); lua_pushstring(L,"write"); lua_pushboolean(L, (st.st_mode & S_IWUSR)==0?0:1); lua_settable(L,-3); lua_pushstring(L,"exec"); lua_pushboolean(L, (st.st_mode & S_IXUSR)==0?0:1); lua_settable(L,-3); //end owner lua_settable(L,-3); lua_pushstring(L,"group"); lua_newtable(L); lua_pushstring(L,"read"); lua_pushboolean(L, (st.st_mode & S_IRGRP)==0?0:1); lua_settable(L,-3); lua_pushstring(L,"write"); lua_pushboolean(L, (st.st_mode & S_IWGRP)==0?0:1); lua_settable(L,-3); lua_pushstring(L,"exec"); lua_pushboolean(L, (st.st_mode & S_IXGRP)==0?0:1); lua_settable(L,-3); //end owner lua_settable(L,-3); lua_pushstring(L,"other"); lua_newtable(L); lua_pushstring(L,"read"); lua_pushboolean(L, (st.st_mode & S_IROTH)==0?0:1); lua_settable(L,-3); lua_pushstring(L,"write"); lua_pushboolean(L, (st.st_mode & S_IWOTH)==0?0:1); lua_settable(L,-3); lua_pushstring(L,"exec"); lua_pushboolean(L, (st.st_mode & S_IXOTH)==0?0:1); lua_settable(L,-3); //end owner lua_settable(L,-3); // end permission lua_settable(L,-3); } else { lua_newtable(L); } return 1; } static int l_file_info(lua_State* L) { const char* path = luaL_checkstring(L,1); l_file_stat(L,path); return 1; } static int l_file_move(lua_State* L) { const char* old = luaL_checkstring(L,1); const char* new = luaL_checkstring(L,2); //printf("MOVE %s to %s\n",old,new); lua_pushboolean(L, rename(old,new)==0); return 1; } static int l_send_file(lua_State* L) { int fromfd, tofd, ret; size_t sz = 0; char* old = NULL; char* new = NULL; if(lua_isnumber(L,1)) { fromfd = (int)luaL_checknumber(L,1); } else { old = (char*)luaL_checkstring(L,1); if((fromfd = open(old, O_RDONLY)) < 0) { lua_pushboolean(L,0); goto end_send_file; } struct stat st; if(stat(old, &st)!=0) { lua_pushboolean(L,0); goto end_send_file; } sz = st.st_size; } if(lua_isnumber(L,2)) { tofd = (int) luaL_checknumber(L,2); } else { new = (char*)luaL_checkstring(L,2); if (unlink(new) < 0 && errno != ENOENT) { lua_pushboolean(L,0); goto end_send_file; } if((tofd = open(new, O_WRONLY | O_CREAT, 0600)) < 0) { lua_pushboolean(L,0); goto end_send_file; } } if(lua_isnumber(L,3)) { sz = (size_t) luaL_checknumber(L,3); } off_t off = 0; int read = 0; while ( sz > 0 && read != sz && ( ((ret = sendfile(tofd, fromfd, &off, sz - read)) >= 0) || (errno == EAGAIN) ) ) { if(ret < 0) ret = 0; read += ret; } if(read != sz) { lua_pushboolean(L,0); goto end_send_file; } lua_pushboolean(L,1); end_send_file: if(fromfd >= 0 && old) { (void) close(fromfd); } if(tofd >= 0 && new) { (void) close(tofd); } return 1; } static int l_read_dir(lua_State* L) { const char* path = luaL_checkstring(L,1); const char* prefix = luaL_checkstring(L,2); DIR *d; struct dirent *dir; d = opendir(path); char buff[1024]; lua_newtable(L); if (d) { int id=0; while ((dir = readdir(d)) != NULL) { //ignore curent directory, parent directory if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..")==0/*|| *(dir->d_name)=='.'*/) continue; sprintf(buff,"%s/%s",path,dir->d_name); lua_pushnumber(L,id); //lua_pushstring(L,buff); l_file_stat(L,buff); lua_pushstring(L,"filename"); lua_pushstring(L,dir->d_name); lua_settable(L,-3); sprintf(buff,"%s/%s",prefix,dir->d_name); //printf("FILE %s\n",buff ); lua_pushstring(L,"path"); lua_pushstring(L,buff); lua_settable(L,-3); lua_settable(L,-3); id++; } closedir(d); } else { lua_pushstring(L,"error"); lua_pushstring(L,"Resource not found"); lua_settable(L,-3); } return 1; } static int l_chown(lua_State* L) { const char* path = luaL_checkstring(L,1); int id = luaL_checknumber(L,2); int gid = luaL_checknumber(L,3); lua_pushboolean(L, chown(path,id,gid) == 0); return 1; } static int l_mkdir(lua_State* L) { const char* path = luaL_checkstring(L,1); lua_pushboolean(L, mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0); return 1; } static int l_exist(lua_State* L) { const char* path = luaL_checkstring(L,1); lua_pushboolean(L,access( path, F_OK ) != -1 ); return 1; } static int is_dir(const char* f) { struct stat st; if(stat(f, &st) == -1) return -1; // unknow else if(st.st_mode & S_IFDIR) return 1; else return 0; } static int l_is_dir(lua_State *L) { const char *file = (char *)luaL_checkstring(L, 1); lua_pushboolean(L, is_dir(file) == 1); return 1; } static int _recursive_delete(const char* path) { if(is_dir(path) == 1) { DIR *d; struct dirent *dir; d = opendir(path); char buff[1024]; if (d) { while ((dir = readdir(d)) != NULL) { //ignore current & parent dir if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..")==0) continue; // get the file sprintf(buff,"%s/%s",path,dir->d_name); if(_recursive_delete(buff) == -1) return -1; } closedir(d); // remove dir if(rmdir(path) != 0) return -1; } else return -1; } else { // file remove if(remove(path) != 0) return -1; } return 0; } static int l_delete(lua_State* L) { const char* f = luaL_checkstring(L,1); lua_pushboolean(L,_recursive_delete(f) == 0); return 1; } /* * Only use this for simple command * Be careful to expose this function * to user. This can cause a serious * security problem */ static int l_cmd_open(lua_State* L) { FILE *fp; const char* cmd = luaL_checkstring(L,1); /* Open the command for reading. */ fp = popen(cmd, "r"); if (fp == NULL) { lua_pushnil(L); return 1; } /*return the fd to lua * user can use this to read the output data*/ intptr_t pt = (intptr_t)fp; lua_pushnumber(L, pt); return 1; } static int l_cmd_read(lua_State* L) { /* Read the output a line at a time - output it. read user defined data of std */ FILE * fd; intptr_t pt = (intptr_t)luaL_checknumber(L, 1); fd = (FILE*)pt; if(fd == NULL) { lua_pushnil(L); return 1; } char buff[1024]; if(fgets(buff, sizeof(buff)-1, fd) != NULL) { lua_pushstring(L,buff); } else { lua_pushnil(L); } /* close */ //pclose(fp); return 1; } static int l_cmd_close(lua_State* L) { /* Read the output a line at a time - output it. read user defined data of std */ FILE * fd; intptr_t pt = (intptr_t)luaL_checknumber(L, 1); fd = (FILE*)pt; if(fd == NULL) { pclose(fd); } return 0; } /*zip file handler * using miniz to compress and uncompress zip file */ static int l_unzip(lua_State* L) { const char* src = luaL_checkstring(L,1); const char* dest = luaL_checkstring(L,2); if(zip_extract(src, dest, NULL, NULL) == -1) { lua_pushboolean(L,0); return 1; } lua_pushboolean(L,1); return 1; } static int _add_to_zip(struct zip_t * zip, const char* path, const char* root) { int st = is_dir(path); if(st == -1) return -1; char p1[MAX_PATH_LEN]; char p2[MAX_PATH_LEN]; if(st) { // read directory DIR *d; struct dirent *dir; //struct stat st; d = opendir(path); if (d) { while ((dir = readdir(d)) != NULL) { //ignore curent directory, parent directory if(strcmp(dir->d_name,".") == 0 || strcmp(dir->d_name,"..")==0) continue; // add file to zip snprintf(p1,MAX_PATH_LEN,"%s/%s", path, dir->d_name); snprintf(p2,MAX_PATH_LEN,"%s/%s",root,dir->d_name); if(_add_to_zip(zip,p1,p2) == -1) { return -1; } } closedir(d); } } else { // if it is a file // add it to zip if(zip_entry_open(zip, root) == -1) return -1; if(zip_entry_fwrite(zip, path) == -1) return -1; zip_entry_close(zip); } return 0; } static int l_zip(lua_State* L) { const char* src = luaL_checkstring(L,1); const char* dest = luaL_checkstring(L,2); // create a zip handler struct zip_t *zip = zip_open(dest, ZIP_DEFAULT_COMPRESSION_LEVEL, 0); if(zip == NULL) goto pfalse; if(_add_to_zip(zip,src,"") == -1) goto pfalse; zip_close(zip); lua_pushboolean(L,1); return 1; // return false pfalse: // TODO remove if filed is created if(zip) zip_close(zip); lua_pushboolean(L,0); return 1; } static int l_getenv(lua_State* L) { const char* name = luaL_checkstring(L,1); if(!name) { lua_pushnil(L); return 1; } char * value = getenv(name); lua_pushstring(L, value); return 1; } static int l_setenv(lua_State* L) { const char* name = luaL_checkstring(L,1); const char* value = luaL_checkstring(L,2); const int force = luaL_checknumber(L,3); if(!name) { lua_pushboolean(L, 0); return 1; } if(!value) { lua_pushboolean(L, 0); return 1; } int ret = setenv(name, value, force); if(ret != 0) { lua_pushboolean(L, 0); return 1; } lua_pushboolean(L,1); return 1; } static int l_unsetenv(lua_State* L) { const char* name = luaL_checkstring(L,1); if(!name) { lua_pushboolean(L, 0); return 1; } int ret = unsetenv(name); if(ret != 0) { lua_pushboolean(L, 0); return 1; } lua_pushboolean(L,1); return 1; } static int l_gethomedir(lua_State* L) { uid_t uid = (uid_t) luaL_checknumber(L,1); if(uid < 0) { lua_pushnil(L); return 1; } struct passwd *pw = getpwuid(uid); if (pw == NULL) { lua_pushnil(L); return 1; } lua_pushstring(L, pw->pw_dir); return 1; } static int l_trim(lua_State *L) { char *str = strdup((char *)luaL_checkstring(L, 1)); const char *tok = luaL_checkstring(L, 2); trim(str, tok[0]); lua_pushstring(L, (const char *)str); free(str); return 1; } static const struct luaL_Reg _lib [] = { {"auth", l_check_login}, {"read_dir",l_read_dir}, {"file_stat",l_file_info}, {"uid",l_getuid}, {"setuid", l_setuid}, {"setgid", l_setgid}, {"fork", l_fork}, {"kill", l_kill}, {"waitpid", l_waitpid}, {"trim", l_trim}, {"chown",l_chown}, {"delete", l_delete}, {"exists",l_exist}, {"mkdir",l_mkdir}, {"cmdopen",l_cmd_open}, {"cmdread",l_cmd_read}, {"cmdclose",l_cmd_close}, {"move",l_file_move}, {"unzip",l_unzip}, {"zip",l_zip}, {"getenv",l_getenv}, {"setenv",l_setenv}, {"unsetenv",l_unsetenv}, {"home_dir",l_gethomedir}, {"send_file", l_send_file}, {"is_dir", l_is_dir}, {NULL,NULL} }; int luaopen_ulib(lua_State *L) { luaL_newlib(L, _lib); return 1; }