win32-service.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /**
  2. * saop: smtp authentication over pop3
  3. * Copyright (C) 2007 Juan José Gutiérrez de Quevedo <juanjo@iteisa.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; version 2 of the License
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. *
  18. * @author Juan José Gutiérrez de Quevedo <juanjo@iteisa.com>
  19. */
  20. #include <stdio.h>
  21. #include <windows.h>
  22. #define SERVICE_NAME "saop: smtp authentication over pop3"
  23. #define SERVICE_SHORT_NAME "saop"
  24. #define SERVICE_DESCRIPTION_TEXT "Adds LOGIN authentication to an SMTP server. Users are authenticated against a pop3 server, an imap4 server or a file"
  25. /* macros */
  26. #define ChangeServiceStatus(x,y,z) y.dwCurrentState=z; SetServiceStatus(x,&y);
  27. #define MIN(x,y) (((x)<(y))?(x):(y))
  28. #define cmp(x,y) strncmp(x,y,strlen(y))
  29. #define msgbox(x,y) MessageBox(NULL,x,"Error from " SERVICE_NAME,MB_OK|y)
  30. #define winerror(x) msgbox(x,MB_ICONERROR)
  31. #define winmessage(x) msgbox(x,MB_ICONINFORMATION)
  32. #define _(x) x
  33. /**
  34. * The docs on microsoft's web don't seem very clear, so I have
  35. * looked at the stunnel source code to understand how this thing
  36. * works. What you see here is still original source, but is
  37. * "inspired" by stunnel's source code (gui.c mainly).
  38. * It's the real minimum needed to install, start and stop services
  39. */
  40. extern int quit;
  41. extern int saop_main(int,char **);
  42. SERVICE_STATUS service_status;
  43. SERVICE_STATUS_HANDLE service_status_handle;
  44. int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int);
  45. static void WINAPI service_main(DWORD,LPTSTR*);
  46. static void WINAPI handler(DWORD);
  47. static int service_install();
  48. static int service_uninstall();
  49. int WINAPI WinMain(HINSTANCE instance,HINSTANCE previous_instance,LPSTR cmdline,int cmdshow)
  50. {
  51. if(!cmp(cmdline,"-service"))
  52. {
  53. SERVICE_TABLE_ENTRY service_table[]={
  54. {SERVICE_NAME,service_main},
  55. {NULL,NULL}
  56. };
  57. if(0==StartServiceCtrlDispatcher(service_table))
  58. {
  59. winerror("Error starting service dispatcher.");
  60. return -1;
  61. }
  62. }
  63. else if(!cmp(cmdline,"-install"))
  64. service_install();
  65. else if(!cmp(cmdline,"-uninstall"))
  66. service_uninstall();
  67. else
  68. saop_main(0,NULL);
  69. return 0;
  70. }
  71. static int service_install()
  72. {
  73. SC_HANDLE scm,service_handle;
  74. SERVICE_DESCRIPTION sd;
  75. char filename[1024];
  76. char exepath[2048];
  77. if(NULL==(scm=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE)))
  78. {
  79. winerror(_("Error opening connection to the Service Manager."));
  80. exit(-1);
  81. }
  82. if(0==GetModuleFileName(NULL,filename,sizeof(filename)))
  83. {
  84. winerror(_("Error getting the file name of the process."));
  85. exit(-1);
  86. }
  87. snprintf(exepath,sizeof(exepath),"\"%s\" -service",filename);
  88. service_handle=CreateService(
  89. scm, /* scm handle */
  90. SERVICE_SHORT_NAME, /* service name */
  91. SERVICE_NAME, /* display name */
  92. SERVICE_ALL_ACCESS, /* desired access */
  93. SERVICE_WIN32_OWN_PROCESS, /* service type */
  94. SERVICE_AUTO_START, /* start type */
  95. SERVICE_ERROR_NORMAL, /* error control */
  96. exepath, /* executable path with arguments */
  97. NULL, /* load group */
  98. NULL, /* tag for group id */
  99. NULL, /* dependencies */
  100. NULL, /* user name */
  101. NULL); /* password */
  102. if(NULL==service_handle)
  103. {
  104. winerror("Error creating service. Already installed?");
  105. exit(-1);
  106. }
  107. else
  108. winmessage("Service successfully installed.");
  109. /*
  110. * createservice doesn't have a field for description
  111. * so we use ChangeServiceConfig2
  112. */
  113. sd.lpDescription=SERVICE_DESCRIPTION_TEXT;
  114. ChangeServiceConfig2(service_handle,SERVICE_CONFIG_DESCRIPTION,(void *)&sd);
  115. CloseServiceHandle(service_handle);
  116. CloseServiceHandle(scm);
  117. return 0;
  118. }
  119. static int service_uninstall()
  120. {
  121. SC_HANDLE scm,service_handle;
  122. SERVICE_STATUS status;
  123. if(NULL==(scm=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE)))
  124. {
  125. winerror(_("Error opening connection to the Service Manager."));
  126. exit(-1);
  127. }
  128. if(NULL==(service_handle=OpenService(scm,SERVICE_SHORT_NAME,SERVICE_QUERY_STATUS|DELETE)))
  129. {
  130. winerror(_("Error opening service."));
  131. CloseServiceHandle(scm);
  132. exit(-1);
  133. }
  134. if(0==QueryServiceStatus(service_handle,&status))
  135. {
  136. winerror(_("Error querying service."));
  137. CloseServiceHandle(scm);
  138. CloseServiceHandle(service_handle);
  139. exit(-1);
  140. }
  141. if(SERVICE_STOPPED!=status.dwCurrentState)
  142. {
  143. winerror(SERVICE_NAME _(" is still running. Stop it before trying to uninstall it."));
  144. CloseServiceHandle(scm);
  145. CloseServiceHandle(service_handle);
  146. exit(-1);
  147. }
  148. if(0==DeleteService(service_handle))
  149. {
  150. winerror(_("Error deleting service."));
  151. CloseServiceHandle(scm);
  152. CloseServiceHandle(service_handle);
  153. exit(-1);
  154. }
  155. CloseServiceHandle(scm);
  156. CloseServiceHandle(service_handle);
  157. winmessage(_("Service successfully uninstalled."));
  158. return 0;
  159. }
  160. static void WINAPI service_main(DWORD argc,LPTSTR *argv)
  161. {
  162. /* configure service_status structure */
  163. service_status.dwServiceType=SERVICE_WIN32;
  164. service_status.dwControlsAccepted=0;
  165. service_status.dwWin32ExitCode=NO_ERROR;
  166. service_status.dwServiceSpecificExitCode=NO_ERROR;
  167. service_status.dwCheckPoint=0;
  168. service_status.dwWaitHint=0;
  169. service_status.dwControlsAccepted|=SERVICE_ACCEPT_STOP;
  170. service_status_handle=RegisterServiceCtrlHandler(SERVICE_NAME,handler);
  171. if(0!=service_status_handle)
  172. {
  173. /* set service status */
  174. ChangeServiceStatus(service_status_handle,service_status,SERVICE_RUNNING);
  175. /* now start our main program */
  176. quit=0;
  177. saop_main(argc,argv);
  178. /* when we are here, we have been stopped */
  179. ChangeServiceStatus(service_status_handle,service_status,SERVICE_STOP_PENDING);
  180. ChangeServiceStatus(service_status_handle,service_status,SERVICE_STOPPED);
  181. }
  182. }
  183. static void WINAPI handler(DWORD code)
  184. {
  185. if(SERVICE_CONTROL_STOP==code)
  186. {
  187. quit=1;
  188. ChangeServiceStatus(service_status_handle,service_status,SERVICE_STOP_PENDING);
  189. }
  190. }