PageRenderTime 2799ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/opendomo-cgi/src/secfunc.c

http://opendomo.googlecode.com/
C | 282 lines | 187 code | 49 blank | 46 comment | 72 complexity | 1be8fa140d94c5ee3197b614b37ffdc9 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*****************************************************************************
  2. * This file is part of the OpenDomo project.
  3. * Copyright(C) 2011 OpenDomo Services SL
  4. *
  5. * Daniel Lerch Hostalot <dlerch@opendomo.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *****************************************************************************/
  20. /**
  21. @file secfunc.c
  22. @brief Security related functions
  23. */
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <limits.h>
  28. #include <sys/types.h>
  29. #include <sys/wait.h>
  30. #include <sys/stat.h>
  31. #include <fcntl.h>
  32. #include <errno.h>
  33. #include <paths.h>
  34. #include <grp.h>
  35. #include <syslog.h>
  36. #include "secfunc.h"
  37. // {{{ sstrncpy()
  38. /// Safe strncpy
  39. void sstrncpy(char *dst, const char *src, size_t size)
  40. {
  41. size_t len = size;
  42. char* dstptr = dst;
  43. char* srcptr = (char*)src;
  44. if (len && --len)
  45. do { if(!(*dstptr++ = *srcptr++)) break; } while(--len);
  46. if (!len && size) *dstptr=0;
  47. }
  48. // }}}
  49. // {{{ sstrncat()
  50. /// Safe strncat
  51. void sstrncat(char *dst, const char *src, size_t size)
  52. {
  53. size_t len = size;
  54. size_t dstlen;
  55. char* dstptr = dst;
  56. char* srcptr = (char*)src;
  57. while(len-- && *dstptr)
  58. dstptr++;
  59. dstlen = dstptr-dst;
  60. if(!(len=size-dstlen))
  61. return;
  62. while(*srcptr)
  63. {
  64. if(len!=1)
  65. {
  66. *dstptr++ = *srcptr;
  67. len--;
  68. }
  69. srcptr++;
  70. }
  71. *dstptr=0;
  72. }
  73. // }}}
  74. // {{{ is_valid_utf8()
  75. /// Returns 1 if is a valid UTF code
  76. int is_valid_utf8(const unsigned char *input)
  77. {
  78. const unsigned char *c = input;
  79. int i;
  80. for(c=input; *c; c += (i+1))
  81. {
  82. if(!(*c & 0x80)) i = 0;
  83. else if(!(*c & 0xc0) == 0x80) return 0;
  84. else if(!(*c & 0xe0) == 0xc0) i = 1;
  85. else if(!(*c & 0xf0) == 0xe0) i = 2;
  86. else if(!(*c & 0xf8) == 0xf0) i = 3;
  87. else if(!(*c & 0xfc) == 0xf8) i = 4;
  88. else if(!(*c & 0xfe) == 0xfc) i = 5;
  89. while(i-- > 0)
  90. if((*(c+i) & 0xc0) != 0x80)
  91. return 0;
  92. }
  93. return 1;
  94. }
  95. // }}}
  96. /// Open a file handler for dev/null
  97. static int open_devnull(int fd)
  98. {
  99. FILE *f = 0;
  100. if (!fd) f = freopen(_PATH_DEVNULL, "rb", stdin);
  101. else if (fd == 1) f = freopen(_PATH_DEVNULL, "wb", stdout);
  102. else if (fd == 2) f = freopen(_PATH_DEVNULL, "wb", stderr);
  103. return (f && fileno(f) == fd);
  104. }
  105. // {{{ sanitize_files()
  106. /// Sanitize files
  107. int sanitize_files(void)
  108. {
  109. int fd, fds;
  110. struct stat st;
  111. if ((fds = getdtablesize()) == -1)
  112. fds = 256;
  113. for (fd = 3; fd < fds; fd++)
  114. close(fd);
  115. for (fd = 0; fd < 3; fd++)
  116. if (fstat(fd, &st) == -1 && (errno != EBADF || !open_devnull(fd)))
  117. return -1;
  118. return 0;
  119. }
  120. // }}}
  121. // {{{ sfork()
  122. /// Safe fork
  123. pid_t sfork()
  124. {
  125. pid_t childpid;
  126. if( (childpid==fork())==-1)
  127. return -1;
  128. if(childpid!=0)
  129. return childpid;
  130. sanitize_files();
  131. // drop provileges
  132. gid_t newgid = getgid(), oldgid = getegid();
  133. uid_t newuid = getuid(), olduid = geteuid();
  134. if (!olduid) setgroups(1, &newgid);
  135. if(newgid != oldgid)
  136. setregid(newgid, newgid);
  137. if(newuid != olduid)
  138. setregid(newuid, newuid);
  139. return 0;
  140. }
  141. // }}}
  142. // {{{ spopen()
  143. /// Safe popen
  144. spipe_t *spopen(const char *path, char *const argv[], char *const envp[])
  145. {
  146. int stdin_pipe[2];
  147. int stdout_pipe[2];
  148. spipe_t *p;
  149. if( !(p=(spipe_t*)malloc(sizeof(spipe_t))))
  150. return 0;
  151. p->read_fd = p->write_fd = 0;
  152. p->child_pid = -1;
  153. if(pipe(stdin_pipe)==-1)
  154. {
  155. free(p);
  156. return 0;
  157. }
  158. if(pipe(stdout_pipe)==-1)
  159. {
  160. close(stdin_pipe[1]);
  161. close(stdin_pipe[0]);
  162. free(p);
  163. return 0;
  164. }
  165. if( !(p->read_fd=fdopen(stdout_pipe[0], "r")))
  166. {
  167. close(stdout_pipe[1]);
  168. close(stdout_pipe[0]);
  169. close(stdin_pipe[1]);
  170. close(stdin_pipe[0]);
  171. free(p);
  172. return 0;
  173. }
  174. if( !(p->write_fd=fdopen(stdin_pipe[1], "w")))
  175. {
  176. fclose(p->read_fd);
  177. close(stdout_pipe[1]);
  178. close(stdin_pipe[1]);
  179. close(stdin_pipe[0]);
  180. free(p);
  181. return 0;
  182. }
  183. if((p->child_pid=sfork())==-1)
  184. {
  185. fclose(p->write_fd);
  186. fclose(p->read_fd);
  187. close(stdout_pipe[1]);
  188. close(stdin_pipe[0]);
  189. free(p);
  190. return 0;
  191. }
  192. if(!p->child_pid)
  193. {
  194. close(stdout_pipe[0]);
  195. close(stdin_pipe[1]);
  196. if(stdin_pipe[0] != 0)
  197. {
  198. dup2(stdin_pipe[0], 0);
  199. close(stdin_pipe[0]);
  200. }
  201. if(stdout_pipe[1] != 1)
  202. {
  203. dup2(stdout_pipe[1], 1);
  204. close(stdout_pipe[1]);
  205. }
  206. execve(path, argv, envp);
  207. exit(127);
  208. }
  209. close(stdout_pipe[1]);
  210. close(stdin_pipe[0]);
  211. return p;
  212. }
  213. // }}}
  214. // {{{ spclose()
  215. /// Safe pclose
  216. int spclose(spipe_t *p)
  217. {
  218. int status;
  219. pid_t pid;
  220. if(p->child_pid!=-1)
  221. {
  222. do { pid = waitpid(p->child_pid, &status, 0); }
  223. while( pid==-1 && errno==EINTR);
  224. }
  225. if(p->read_fd) fclose(p->read_fd);
  226. if(p->write_fd) fclose(p->write_fd);
  227. free(p);
  228. if(pid!=-1 && WIFEXITED(status))
  229. return WEXITSTATUS(status);
  230. else
  231. return (pid==-1 ? -1 : 0);
  232. }
  233. // }}}