launcherd.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #define _GNU_SOURCE //pipe2()
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <grp.h>
  5. #include <paths.h>
  6. #include <pwd.h>
  7. #include <signal.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <sys/prctl.h>
  12. #include <sys/socket.h>
  13. #include <unistd.h>
  14. #include "launcherd.h"
  15. static int switchToUser( struct passwd* user ){
  16. /*** switch gid, groups and uid ***/
  17. if( setgid( user->pw_gid ) ) goto l_perror;
  18. if( initgroups(user->pw_name, user->pw_gid) ) goto l_perror;
  19. if( setuid( user->pw_uid ) ) goto l_perror;
  20. /*** check they really switched ***/
  21. if( getgid() != user->pw_gid || getegid() != user->pw_gid ||
  22. getuid() != user->pw_uid || geteuid() != user->pw_uid ){
  23. printf( "[launcherd] Failed switch uid or gid\n" );
  24. return -2;
  25. }
  26. /*** if target user is root, no more checks is needed ***/
  27. if( !user->pw_uid || !user->pw_gid ) return 0;
  28. /*** extra check if target user not root ***/
  29. if( !setuid(0) || !seteuid(0) ){
  30. printf( "[launcherd] Could not drop root privileges!\n" );
  31. return -3;
  32. }
  33. return 0;
  34. l_perror:
  35. perror( "[launcherd] switch user" );
  36. return -1;
  37. }
  38. /**************************************************
  39. func execute
  40. set environment, cd to home,
  41. route stdin, stdout, stderr to /dev/null
  42. and attempt to exec program from user
  43. input
  44. user - user to run as
  45. programm - path to executable
  46. return
  47. not return on success
  48. errno on error
  49. **************************************************/
  50. static int execute( struct passwd* user, char* programm, int pipe ){
  51. /*** args ***/
  52. char* execArgs[] = { programm, NULL };
  53. /*** env ***/
  54. char eUSER[64];
  55. char eLOGNAME[64];
  56. char eHOME[128];
  57. char eSHELL[128];
  58. char ePATH[] = "PATH=" _PATH_STDPATH;
  59. char* execEnv[] = { eUSER, eLOGNAME, eHOME, eSHELL, ePATH, NULL };
  60. if( strlen(user->pw_name) > 32 || strlen(user->pw_dir) > 120 || strlen(user->pw_shell) > 120 ){
  61. printf( "[launcherd] username or home or shell too long\n" );
  62. return ECANCELED;
  63. }
  64. sprintf( eUSER, "USER=%s", user->pw_name );
  65. sprintf( eLOGNAME, "LOGNAME=%s", user->pw_name );
  66. sprintf( eHOME, "HOME=%s", user->pw_dir );
  67. sprintf( eSHELL, "SHELL=%s", user->pw_shell );
  68. /*** pwd ***/
  69. if( chdir(user->pw_dir) ){
  70. printf( "[launcherd] Cannot cd to [%s], using [/] instead\n", user->pw_dir );
  71. if( chdir("/") ){
  72. printf( "[launcherd] chdir\n" );
  73. return ECANCELED;
  74. }
  75. }
  76. printf( "[launcherd] Trying to start [%s] from user [%s]\n", programm, user->pw_name );
  77. /*** route stdin, stdout and stderr to /dev/null ***/
  78. if( fileno( freopen(_PATH_DEVNULL, "rb", stdin ) ) != 0 ) return EBADF;
  79. if( fileno( freopen(_PATH_DEVNULL, "wb", stdout) ) != 1 ) return EBADF;
  80. if( fileno( freopen(_PATH_DEVNULL, "wb", stderr) ) != 2 ) return EBADF;
  81. /*** exec ***/
  82. execve( programm, execArgs, execEnv );
  83. return errno;
  84. }
  85. /**************************************
  86. func executeFromUser
  87. switch to user and execute prorgamm
  88. return
  89. not return on success
  90. if return then error
  91. **************************************/
  92. static int executeFromUser( struct launcherdRequest* execrq, int pipe ){
  93. int savedErrno;
  94. struct passwd* user;
  95. //get user data from /etc/passwd
  96. user = getpwnam( execrq->username );
  97. if( !user ){
  98. if( !errno ) printf( "[launcherd] User [%s] not found.\n", execrq->username );
  99. else perror( "[launcherd] getpwnam" );
  100. savedErrno = ECANCELED;
  101. goto l_error;
  102. }
  103. //switch to user
  104. if( switchToUser(user) ){
  105. savedErrno = ECANCELED;
  106. goto l_error;
  107. }
  108. //try to execute;
  109. savedErrno = execute( user, execrq->programm, pipe );
  110. l_error:
  111. return write( pipe, &savedErrno, sizeof(savedErrno) );
  112. }
  113. /**********************************************
  114. func launcherdListen
  115. listen control socket and handle connection
  116. input
  117. mySocket - socket to listen
  118. return
  119. 0 on exit if socket close from other side
  120. not 0 on error
  121. **********************************************/
  122. static int launcherdListen( int mySocket ){
  123. int res;
  124. int execRes;
  125. int pipes[2];
  126. struct launcherdRequest rq;
  127. printf( "[launcherd] Listen\n" );
  128. l_listen:
  129. //receive request from socket
  130. if( recv(mySocket, &rq, sizeof(rq), MSG_WAITALL) != sizeof(rq) ){
  131. if( errno ){
  132. perror( "[launcherd] recv" );
  133. return -1;
  134. }
  135. printf( "[launcherd] Socket seems has been closed. Exiting.\n" );
  136. return 0;
  137. }
  138. //strings must be null-terminated
  139. rq.username[sizeof(rq.username)-1] = 0x00;
  140. rq.programm[sizeof(rq.programm)-1] = 0x00;
  141. //create pipes to check execute result
  142. res = pipe2( pipes, O_CLOEXEC );
  143. if( res ){
  144. perror( "[launcherd] pipe2" );
  145. return -2;
  146. }
  147. //fork process to execute requested program
  148. res = fork();
  149. if( res < 0 ){
  150. perror( "[launcherd] fork" );
  151. return -3;
  152. }
  153. //prepare and exec in the child process
  154. if( !res ){//child
  155. close( mySocket );
  156. close( pipes[0] );
  157. executeFromUser( &rq, pipes[1] );
  158. exit( 1 );//exit if exec failed
  159. }
  160. //close child pipe
  161. close( pipes[1] );
  162. //read and print execute result from child over pipe
  163. res = read( pipes[0], &execRes, sizeof(execRes) );
  164. if( res != sizeof(execRes) ) printf( "[launcherd] Success.\n" );
  165. else printf( "[launcherd] Failed: %s.\n", strerror(execRes) );
  166. //close our pipe
  167. close( pipes[0] );
  168. //listen next request
  169. goto l_listen;
  170. }
  171. /********************************************
  172. func launcherdStart
  173. create control socket and start launcherd
  174. return
  175. negative on error
  176. positive as control socket
  177. ********************************************/
  178. int launcherdStart( void ){
  179. int res;
  180. int sockets[2];
  181. //create sockets
  182. res = socketpair( AF_UNIX, SOCK_STREAM, 0, sockets );
  183. if( res ){
  184. perror( "[launcherd] socketpair" );
  185. return -1;
  186. }
  187. //fork process
  188. res = fork();
  189. if( res < 0 ){
  190. perror( "[launcherd] fork" );
  191. return -2;
  192. }
  193. //start listen socket in the child process
  194. if( !res ){//child
  195. close( sockets[0] );
  196. prctl( PR_SET_NAME, "launcherd", 0, 0, 0 );
  197. signal( SIGCHLD, SIG_IGN );
  198. signal( SIGPIPE, SIG_IGN );
  199. res = launcherdListen( sockets[1] );
  200. printf( "[launcherd] Exiting with code: %i\n", res );
  201. close( sockets[1] );
  202. exit( res );
  203. }
  204. //return socket for communicate with child process
  205. close( sockets[1] );
  206. return sockets[0];
  207. }