PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/responder/nss/nsssrv.c

https://github.com/pavka/sssd
C | 426 lines | 326 code | 65 blank | 35 comment | 74 complexity | 116c5668d8135ea3faf18ceca7f10eae MD5 | raw file
  1. /*
  2. SSSD
  3. NSS Responder
  4. Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
  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; either version 3 of the License, or
  8. (at your option) any later version.
  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. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <stdio.h>
  17. #include <unistd.h>
  18. #include <fcntl.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <sys/socket.h>
  22. #include <sys/un.h>
  23. #include <string.h>
  24. #include <sys/time.h>
  25. #include <errno.h>
  26. #include "popt.h"
  27. #include "util/util.h"
  28. #include "responder/nss/nsssrv.h"
  29. #include "responder/nss/nsssrv_mmap_cache.h"
  30. #include "responder/common/negcache.h"
  31. #include "db/sysdb.h"
  32. #include "confdb/confdb.h"
  33. #include "dbus/dbus.h"
  34. #include "sbus/sssd_dbus.h"
  35. #include "responder/common/responder_packet.h"
  36. #include "responder/common/responder.h"
  37. #include "providers/data_provider.h"
  38. #include "monitor/monitor_interfaces.h"
  39. #include "sbus/sbus_client.h"
  40. #define DEFAULT_PWFIELD "*"
  41. #define DEFAULT_NSS_FD_LIMIT 8192
  42. #define SHELL_REALLOC_INCREMENT 5
  43. #define SHELL_REALLOC_MAX 50
  44. struct sbus_method monitor_nss_methods[] = {
  45. { MON_CLI_METHOD_PING, monitor_common_pong },
  46. { MON_CLI_METHOD_RES_INIT, monitor_common_res_init },
  47. { MON_CLI_METHOD_ROTATE, responder_logrotate },
  48. { NULL, NULL }
  49. };
  50. struct sbus_interface monitor_nss_interface = {
  51. MONITOR_INTERFACE,
  52. MONITOR_PATH,
  53. SBUS_DEFAULT_VTABLE,
  54. monitor_nss_methods,
  55. NULL
  56. };
  57. static errno_t nss_get_etc_shells(TALLOC_CTX *mem_ctx, char ***_shells)
  58. {
  59. int i = 0;
  60. char *sh;
  61. char **shells = NULL;
  62. TALLOC_CTX *tmp_ctx;
  63. errno_t ret;
  64. int size;
  65. tmp_ctx = talloc_new(NULL);
  66. if (!tmp_ctx) return ENOMEM;
  67. shells = talloc_array(tmp_ctx, char *, SHELL_REALLOC_INCREMENT);
  68. if (!shells) {
  69. ret = ENOMEM;
  70. goto done;
  71. }
  72. size = SHELL_REALLOC_INCREMENT;
  73. setusershell();
  74. while ((sh = getusershell())) {
  75. shells[i] = talloc_strdup(shells, sh);
  76. if (!shells[i]) {
  77. endusershell();
  78. ret = ENOMEM;
  79. goto done;
  80. }
  81. DEBUG(6, ("Found shell %s in /etc/shells\n", shells[i]));
  82. i++;
  83. if (i == size) {
  84. size += SHELL_REALLOC_INCREMENT;
  85. if (size > SHELL_REALLOC_MAX) {
  86. DEBUG(0, ("Reached maximum number of shells [%d]. "
  87. "Users may be denied access. "
  88. "Please check /etc/shells for sanity\n",
  89. SHELL_REALLOC_MAX));
  90. break;
  91. }
  92. shells = talloc_realloc(NULL, shells, char *,
  93. size);
  94. if (!shells) {
  95. ret = ENOMEM;
  96. goto done;
  97. }
  98. }
  99. }
  100. endusershell();
  101. if (i + 1 < size) {
  102. shells = talloc_realloc(NULL, shells, char *, i + 1);
  103. if (!shells) {
  104. ret = ENOMEM;
  105. goto done;
  106. }
  107. }
  108. shells[i] = NULL;
  109. *_shells = talloc_move(mem_ctx, &shells);
  110. ret = EOK;
  111. done:
  112. talloc_zfree(tmp_ctx);
  113. return ret;
  114. }
  115. static int nss_get_config(struct nss_ctx *nctx,
  116. struct confdb_ctx *cdb)
  117. {
  118. int ret;
  119. ret = confdb_get_int(cdb, CONFDB_NSS_CONF_ENTRY,
  120. CONFDB_NSS_ENUM_CACHE_TIMEOUT, 120,
  121. &nctx->enum_cache_timeout);
  122. if (ret != EOK) goto done;
  123. ret = confdb_get_int(cdb, CONFDB_NSS_CONF_ENTRY,
  124. CONFDB_NSS_ENTRY_NEG_TIMEOUT, 15,
  125. &nctx->neg_timeout);
  126. if (ret != EOK) goto done;
  127. ret = confdb_get_bool(cdb, CONFDB_NSS_CONF_ENTRY,
  128. CONFDB_NSS_FILTER_USERS_IN_GROUPS, true,
  129. &nctx->filter_users_in_groups);
  130. if (ret != EOK) goto done;
  131. ret = confdb_get_int(cdb, CONFDB_NSS_CONF_ENTRY,
  132. CONFDB_NSS_ENTRY_CACHE_NOWAIT_PERCENTAGE, 50,
  133. &nctx->cache_refresh_percent);
  134. if (ret != EOK) goto done;
  135. if (nctx->cache_refresh_percent < 0 ||
  136. nctx->cache_refresh_percent > 99) {
  137. DEBUG(0,("Configuration error: entry_cache_nowait_percentage is "
  138. "invalid. Disabling feature.\n"));
  139. nctx->cache_refresh_percent = 0;
  140. }
  141. ret = sss_ncache_prepopulate(nctx->ncache, cdb, nctx->rctx);
  142. if (ret != EOK) {
  143. goto done;
  144. }
  145. ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
  146. CONFDB_NSS_PWFIELD, DEFAULT_PWFIELD,
  147. &nctx->pwfield);
  148. if (ret != EOK) goto done;
  149. ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
  150. CONFDB_NSS_OVERRIDE_HOMEDIR, NULL,
  151. &nctx->override_homedir);
  152. if (ret != EOK) goto done;
  153. ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
  154. CONFDB_NSS_FALLBACK_HOMEDIR, NULL,
  155. &nctx->fallback_homedir);
  156. if (ret != EOK) goto done;
  157. ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
  158. CONFDB_NSS_OVERRIDE_SHELL, NULL,
  159. &nctx->override_shell);
  160. if (ret != EOK && ret != ENOENT) goto done;
  161. ret = confdb_get_string_as_list(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
  162. CONFDB_NSS_ALLOWED_SHELL,
  163. &nctx->allowed_shells);
  164. if (ret != EOK && ret != ENOENT) goto done;
  165. ret = confdb_get_string_as_list(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
  166. CONFDB_NSS_VETOED_SHELL,
  167. &nctx->vetoed_shells);
  168. if (ret != EOK && ret != ENOENT) goto done;
  169. ret = nss_get_etc_shells(nctx, &nctx->etc_shells);
  170. if (ret != EOK) goto done;
  171. ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
  172. CONFDB_NSS_SHELL_FALLBACK,
  173. CONFDB_DEFAULT_SHELL_FALLBACK,
  174. &nctx->shell_fallback);
  175. if (ret != EOK) goto done;
  176. ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
  177. CONFDB_NSS_DEFAULT_SHELL,
  178. NULL,
  179. &nctx->default_shell);
  180. if (ret != EOK) goto done;
  181. ret = 0;
  182. done:
  183. return ret;
  184. }
  185. static struct sbus_method nss_dp_methods[] = {
  186. { NULL, NULL }
  187. };
  188. struct sbus_interface nss_dp_interface = {
  189. DP_INTERFACE,
  190. DP_PATH,
  191. SBUS_DEFAULT_VTABLE,
  192. nss_dp_methods,
  193. NULL
  194. };
  195. static void nss_dp_reconnect_init(struct sbus_connection *conn,
  196. int status, void *pvt)
  197. {
  198. struct be_conn *be_conn = talloc_get_type(pvt, struct be_conn);
  199. int ret;
  200. /* Did we reconnect successfully? */
  201. if (status == SBUS_RECONNECT_SUCCESS) {
  202. DEBUG(1, ("Reconnected to the Data Provider.\n"));
  203. /* Identify ourselves to the data provider */
  204. ret = dp_common_send_id(be_conn->conn,
  205. DATA_PROVIDER_VERSION,
  206. "NSS");
  207. /* all fine */
  208. if (ret == EOK) {
  209. handle_requests_after_reconnect(be_conn->rctx);
  210. return;
  211. }
  212. }
  213. /* Failed to reconnect */
  214. DEBUG(0, ("Could not reconnect to %s provider.\n",
  215. be_conn->domain->name));
  216. /* FIXME: kill the frontend and let the monitor restart it ? */
  217. /* nss_shutdown(rctx); */
  218. }
  219. int nss_process_init(TALLOC_CTX *mem_ctx,
  220. struct tevent_context *ev,
  221. struct confdb_ctx *cdb)
  222. {
  223. struct sss_cmd_table *nss_cmds;
  224. struct be_conn *iter;
  225. struct nss_ctx *nctx;
  226. int memcache_timeout;
  227. int ret, max_retries;
  228. int hret;
  229. int fd_limit;
  230. nctx = talloc_zero(mem_ctx, struct nss_ctx);
  231. if (!nctx) {
  232. DEBUG(0, ("fatal error initializing nss_ctx\n"));
  233. return ENOMEM;
  234. }
  235. ret = sss_ncache_init(nctx, &nctx->ncache);
  236. if (ret != EOK) {
  237. DEBUG(0, ("fatal error initializing negative cache\n"));
  238. return ret;
  239. }
  240. nss_cmds = get_nss_cmds();
  241. ret = sss_process_init(nctx, ev, cdb,
  242. nss_cmds,
  243. SSS_NSS_SOCKET_NAME, NULL,
  244. CONFDB_NSS_CONF_ENTRY,
  245. NSS_SBUS_SERVICE_NAME,
  246. NSS_SBUS_SERVICE_VERSION,
  247. &monitor_nss_interface,
  248. "NSS", &nss_dp_interface,
  249. &nctx->rctx);
  250. if (ret != EOK) {
  251. return ret;
  252. }
  253. nctx->rctx->pvt_ctx = nctx;
  254. ret = nss_get_config(nctx, cdb);
  255. if (ret != EOK) {
  256. DEBUG(0, ("fatal error getting nss config\n"));
  257. return ret;
  258. }
  259. /* Enable automatic reconnection to the Data Provider */
  260. ret = confdb_get_int(nctx->rctx->cdb,
  261. CONFDB_NSS_CONF_ENTRY,
  262. CONFDB_SERVICE_RECON_RETRIES,
  263. 3, &max_retries);
  264. if (ret != EOK) {
  265. DEBUG(0, ("Failed to set up automatic reconnection\n"));
  266. return ret;
  267. }
  268. for (iter = nctx->rctx->be_conns; iter; iter = iter->next) {
  269. sbus_reconnect_init(iter->conn, max_retries,
  270. nss_dp_reconnect_init, iter);
  271. }
  272. /* Create the lookup table for netgroup results */
  273. hret = sss_hash_create(nctx, 10, &nctx->netgroups);
  274. if (hret != HASH_SUCCESS) {
  275. DEBUG(0,("Unable to initialize netgroup hash table\n"));
  276. return EIO;
  277. }
  278. /* create mmap caches */
  279. ret = confdb_get_int(nctx->rctx->cdb,
  280. CONFDB_NSS_CONF_ENTRY,
  281. CONFDB_MEMCACHE_TIMEOUT,
  282. 300, &memcache_timeout);
  283. if (ret != EOK) {
  284. DEBUG(0, ("Failed to set up automatic reconnection\n"));
  285. return ret;
  286. }
  287. /* TODO: read cache sizes from configuration */
  288. ret = sss_mmap_cache_init(nctx, "passwd", SSS_MC_PASSWD,
  289. 50000, (time_t)memcache_timeout,
  290. &nctx->pwd_mc_ctx);
  291. if (ret) {
  292. DEBUG(SSSDBG_CRIT_FAILURE, ("passwd mmap cache is DISABLED\n"));
  293. }
  294. ret = sss_mmap_cache_init(nctx, "group", SSS_MC_GROUP,
  295. 50000, (time_t)memcache_timeout,
  296. &nctx->grp_mc_ctx);
  297. if (ret) {
  298. DEBUG(SSSDBG_CRIT_FAILURE, ("group mmap cache is DISABLED\n"));
  299. }
  300. /* Set up file descriptor limits */
  301. ret = confdb_get_int(nctx->rctx->cdb,
  302. CONFDB_NSS_CONF_ENTRY,
  303. CONFDB_SERVICE_FD_LIMIT,
  304. DEFAULT_NSS_FD_LIMIT,
  305. &fd_limit);
  306. if (ret != EOK) {
  307. DEBUG(SSSDBG_FATAL_FAILURE,
  308. ("Failed to set up file descriptor limit\n"));
  309. return ret;
  310. }
  311. responder_set_fd_limit(fd_limit);
  312. DEBUG(SSSDBG_TRACE_FUNC, ("NSS Initialization complete\n"));
  313. return EOK;
  314. }
  315. int main(int argc, const char *argv[])
  316. {
  317. int opt;
  318. poptContext pc;
  319. struct main_context *main_ctx;
  320. int ret;
  321. struct poptOption long_options[] = {
  322. POPT_AUTOHELP
  323. SSSD_MAIN_OPTS
  324. POPT_TABLEEND
  325. };
  326. /* Set debug level to invalid value so we can deside if -d 0 was used. */
  327. debug_level = SSSDBG_INVALID;
  328. pc = poptGetContext(argv[0], argc, argv, long_options, 0);
  329. while((opt = poptGetNextOpt(pc)) != -1) {
  330. switch(opt) {
  331. default:
  332. fprintf(stderr, "\nInvalid option %s: %s\n\n",
  333. poptBadOption(pc, 0), poptStrerror(opt));
  334. poptPrintUsage(pc, stderr, 0);
  335. return 1;
  336. }
  337. }
  338. poptFreeContext(pc);
  339. CONVERT_AND_SET_DEBUG_LEVEL(debug_level);
  340. /* set up things like debug, signals, daemonization, etc... */
  341. debug_log_file = "sssd_nss";
  342. ret = server_setup("sssd[nss]", 0, CONFDB_NSS_CONF_ENTRY, &main_ctx);
  343. if (ret != EOK) return 2;
  344. ret = die_if_parent_died();
  345. if (ret != EOK) {
  346. /* This is not fatal, don't return */
  347. DEBUG(2, ("Could not set up to exit when parent process does\n"));
  348. }
  349. ret = nss_process_init(main_ctx,
  350. main_ctx->event_ctx,
  351. main_ctx->confdb_ctx);
  352. if (ret != EOK) return 3;
  353. /* loop on main */
  354. server_loop(main_ctx);
  355. return 0;
  356. }