| File: | src/usr.sbin/radiusd/radiusd_bsdauth/../radiusd_bsdauth.c |
| Warning: | line 102, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: radiusd_bsdauth.c,v 1.14 2019/12/14 15:56:20 millert Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> |
| 5 | * |
| 6 | * Permission to use, copy, modify, and distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above |
| 8 | * copyright notice and this permission notice appear in all copies. |
| 9 | * |
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ |
| 18 | |
| 19 | #include <sys/types.h> |
| 20 | #include <sys/queue.h> |
| 21 | #include <sys/socket.h> |
| 22 | #include <sys/uio.h> |
| 23 | #include <sys/wait.h> |
| 24 | |
| 25 | #include <bsd_auth.h> |
| 26 | #include <err.h> |
| 27 | #include <errno(*__errno()).h> |
| 28 | #include <fcntl.h> |
| 29 | #include <grp.h> |
| 30 | #include <imsg.h> |
| 31 | #include <login_cap.h> |
| 32 | #include <pwd.h> |
| 33 | #include <stdbool.h> |
| 34 | #include <stdio.h> |
| 35 | #include <stdlib.h> |
| 36 | #include <string.h> |
| 37 | #include <syslog.h> |
| 38 | #include <unistd.h> |
| 39 | |
| 40 | #include "radiusd.h" |
| 41 | #include "radiusd_module.h" |
| 42 | |
| 43 | struct module_bsdauth { |
| 44 | struct module_base *base; |
| 45 | struct imsgbuf ibuf; |
| 46 | char **okgroups; |
| 47 | }; |
| 48 | |
| 49 | /* IPC between priv and main */ |
| 50 | enum { |
| 51 | IMSG_BSDAUTH_OK = 1000, |
| 52 | IMSG_BSDAUTH_NG, |
| 53 | IMSG_BSDAUTH_USERCHECK, |
| 54 | IMSG_BSDAUTH_GROUPCHECK |
| 55 | }; |
| 56 | struct auth_usercheck_args { |
| 57 | size_t userlen; |
| 58 | size_t passlen; |
| 59 | }; |
| 60 | struct auth_groupcheck_args { |
| 61 | size_t userlen; |
| 62 | size_t grouplen; |
| 63 | }; |
| 64 | |
| 65 | __dead__attribute__((__noreturn__)) static void |
| 66 | module_bsdauth_main(void); |
| 67 | static void module_bsdauth_config_set(void *, const char *, int, |
| 68 | char * const *); |
| 69 | static void module_bsdauth_userpass(void *, u_int, const char *, |
| 70 | const char *); |
| 71 | static pid_t start_child(char *, int); |
| 72 | __dead__attribute__((__noreturn__)) static void |
| 73 | fatal(const char *); |
| 74 | |
| 75 | static struct module_handlers module_bsdauth_handlers = { |
| 76 | .userpass = module_bsdauth_userpass, |
| 77 | .config_set = module_bsdauth_config_set |
| 78 | }; |
| 79 | |
| 80 | int |
| 81 | main(int argc, char *argv[]) |
| 82 | { |
| 83 | int ch, pairsock[2], status; |
| 84 | struct imsgbuf ibuf; |
| 85 | struct imsg imsg; |
| 86 | ssize_t n; |
| 87 | size_t datalen; |
| 88 | pid_t pid; |
| 89 | char *saved_argv0; |
| 90 | |
| 91 | while ((ch = getopt(argc, argv, "M")) != -1) |
| 92 | switch (ch) { |
| 93 | case 'M': |
| 94 | module_bsdauth_main(); |
| 95 | /* never return, not rearched here */ |
| 96 | break; |
| 97 | default: |
| 98 | break; |
| 99 | } |
| 100 | saved_argv0 = argv[0]; |
| 101 | argc -= optind; |
| 102 | argv += optind; |
Value stored to 'argv' is never read | |
| 103 | |
| 104 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_CLOEXEC0x8000, PF_UNSPEC0, |
| 105 | pairsock) == -1) |
| 106 | err(EXIT_FAILURE1, "socketpair"); |
| 107 | |
| 108 | openlog(NULL((void *)0), LOG_PID0x01, LOG_DAEMON(3<<3)); |
| 109 | |
| 110 | pid = start_child(saved_argv0, pairsock[1]); |
| 111 | |
| 112 | /* |
| 113 | * Privileged process |
| 114 | */ |
| 115 | setproctitle("[priv]"); |
| 116 | imsg_init(&ibuf, pairsock[0]); |
| 117 | |
| 118 | if (pledge("stdio getpw rpath proc exec", NULL((void *)0)) == -1) |
| 119 | err(EXIT_FAILURE1, "pledge"); |
| 120 | |
| 121 | for (;;) { |
| 122 | if ((n = imsg_read(&ibuf)) <= 0 && errno(*__errno()) != EAGAIN35) |
| 123 | break; |
| 124 | for (;;) { |
| 125 | if ((n = imsg_get(&ibuf, &imsg)) == -1) |
| 126 | break; |
| 127 | if (n == 0) |
| 128 | break; |
| 129 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); |
| 130 | switch (imsg.hdr.type) { |
| 131 | case IMSG_BSDAUTH_USERCHECK: |
| 132 | { |
| 133 | char *user, *pass; |
| 134 | bool_Bool authok = false0; |
| 135 | struct auth_usercheck_args |
| 136 | *args; |
| 137 | |
| 138 | if (datalen < sizeof( |
| 139 | struct auth_usercheck_args)) { |
| 140 | syslog(LOG_ERR3, "Short message"); |
| 141 | break; |
| 142 | } |
| 143 | args = (struct auth_usercheck_args *)imsg.data; |
| 144 | |
| 145 | if (datalen < sizeof(struct auth_usercheck_args) |
| 146 | + args->userlen + args->passlen) { |
| 147 | syslog(LOG_ERR3, "Short message"); |
| 148 | break; |
| 149 | } |
| 150 | user = (char *)(args + 1); |
| 151 | user[args->userlen - 1] = '\0'; |
| 152 | pass = user + args->userlen; |
| 153 | pass[args->passlen - 1] = '\0'; |
| 154 | |
| 155 | if (auth_userokay(user, NULL((void *)0), NULL((void *)0), pass)) |
| 156 | authok = true1; |
| 157 | explicit_bzero(pass, args->passlen); |
| 158 | |
| 159 | imsg_compose(&ibuf, (authok) |
| 160 | ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG, |
| 161 | 0, 0, -1, NULL((void *)0), 0); |
| 162 | break; |
| 163 | } |
| 164 | case IMSG_BSDAUTH_GROUPCHECK: |
| 165 | { |
| 166 | int i; |
| 167 | char *user, *group; |
| 168 | struct passwd *pw; |
| 169 | struct group gr0, *gr; |
| 170 | char g_buf[4096]; |
| 171 | bool_Bool group_ok = false0; |
| 172 | struct auth_groupcheck_args |
| 173 | *args; |
| 174 | |
| 175 | if (datalen < sizeof( |
| 176 | struct auth_groupcheck_args)) { |
| 177 | syslog(LOG_ERR3, "Short message"); |
| 178 | break; |
| 179 | } |
| 180 | args = (struct auth_groupcheck_args *)imsg.data; |
| 181 | if (datalen < |
| 182 | sizeof(struct auth_groupcheck_args) + |
| 183 | args->userlen + args->grouplen) { |
| 184 | syslog(LOG_ERR3, "Short message"); |
| 185 | break; |
| 186 | } |
| 187 | user = (char *)(args + 1); |
| 188 | user[args->userlen - 1] = '\0'; |
| 189 | group = user + args->userlen; |
| 190 | group[args->grouplen - 1] = '\0'; |
| 191 | |
| 192 | user[strcspn(user, ":")] = '\0'; |
| 193 | pw = getpwnam(user); |
| 194 | if (pw == NULL((void *)0)) |
| 195 | goto invalid; |
| 196 | if (getgrnam_r(group, &gr0, g_buf, |
| 197 | sizeof(g_buf), &gr) == -1 || gr == NULL((void *)0)) |
| 198 | goto invalid; |
| 199 | |
| 200 | if (gr->gr_gid == pw->pw_gid) { |
| 201 | group_ok = true1; |
| 202 | goto invalid; |
| 203 | } |
| 204 | for (i = 0; gr->gr_mem[i] != NULL((void *)0); i++) { |
| 205 | if (strcmp(gr->gr_mem[i], pw->pw_name) |
| 206 | == 0) { |
| 207 | group_ok = true1; |
| 208 | goto invalid; |
| 209 | } |
| 210 | } |
| 211 | invalid: |
| 212 | endgrent(); |
| 213 | |
| 214 | imsg_compose(&ibuf, (group_ok) |
| 215 | ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG, |
| 216 | 0, 0, -1, NULL((void *)0), 0); |
| 217 | break; |
| 218 | } |
| 219 | } |
| 220 | imsg_free(&imsg); |
| 221 | imsg_flush(&ibuf); |
| 222 | } |
| 223 | imsg_flush(&ibuf); |
| 224 | } |
| 225 | imsg_clear(&ibuf); |
| 226 | |
| 227 | while (waitpid(pid, &status, 0) == -1) { |
| 228 | if (errno(*__errno()) != EINTR4) |
| 229 | break; |
| 230 | } |
| 231 | exit(WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff)); |
| 232 | } |
| 233 | |
| 234 | static void |
| 235 | module_bsdauth_main(void) |
| 236 | { |
| 237 | int i; |
| 238 | struct module_bsdauth module_bsdauth; |
| 239 | |
| 240 | /* |
| 241 | * main process |
| 242 | */ |
| 243 | setproctitle("[main]"); |
| 244 | openlog(NULL((void *)0), LOG_PID0x01, LOG_DAEMON(3<<3)); |
| 245 | memset(&module_bsdauth, 0, sizeof(module_bsdauth)); |
| 246 | if ((module_bsdauth.base = module_create(STDIN_FILENO0, &module_bsdauth, |
| 247 | &module_bsdauth_handlers)) == NULL((void *)0)) |
| 248 | err(1, "Could not create a module instance"); |
| 249 | |
| 250 | module_drop_privilege(module_bsdauth.base); |
| 251 | |
| 252 | module_load(module_bsdauth.base); |
| 253 | imsg_init(&module_bsdauth.ibuf, 3); |
| 254 | |
| 255 | if (pledge("stdio proc", NULL((void *)0)) == -1) |
| 256 | err(EXIT_FAILURE1, "pledge"); |
| 257 | |
| 258 | while (module_run(module_bsdauth.base) == 0) |
| 259 | ; |
| 260 | |
| 261 | module_destroy(module_bsdauth.base); |
| 262 | imsg_clear(&module_bsdauth.ibuf); |
| 263 | |
| 264 | if (module_bsdauth.okgroups) { |
| 265 | for (i = 0; module_bsdauth.okgroups[i] != NULL((void *)0); i++) |
| 266 | free(module_bsdauth.okgroups[i]); |
| 267 | } |
| 268 | free(module_bsdauth.okgroups); |
| 269 | |
| 270 | exit(EXIT_SUCCESS0); |
| 271 | } |
| 272 | |
| 273 | static void |
| 274 | module_bsdauth_config_set(void *ctx, const char *name, int argc, |
| 275 | char * const * argv) |
| 276 | { |
| 277 | struct module_bsdauth *module = ctx; |
| 278 | int i; |
| 279 | char **groups = NULL((void *)0); |
| 280 | |
| 281 | if (strcmp(name, "restrict-group") == 0) { |
| 282 | if (module->okgroups != NULL((void *)0)) { |
| 283 | module_send_message(module->base, IMSG_NG, |
| 284 | "`restrict-group' is already defined"); |
| 285 | goto on_error; |
| 286 | } |
| 287 | if ((groups = calloc(sizeof(char *), argc + 1)) == NULL((void *)0)) { |
| 288 | module_send_message(module->base, IMSG_NG, |
| 289 | "Out of memory"); |
| 290 | goto on_error; |
| 291 | } |
| 292 | for (i = 0; i < argc; i++) { |
| 293 | if ((groups[i] = strdup(argv[i])) == NULL((void *)0)) { |
| 294 | module_send_message(module->base, |
| 295 | IMSG_NG, "Out of memory"); |
| 296 | goto on_error; |
| 297 | } |
| 298 | } |
| 299 | groups[i] = NULL((void *)0); |
| 300 | module->okgroups = groups; |
| 301 | module_send_message(module->base, IMSG_OK, NULL((void *)0)); |
| 302 | } else if (strncmp(name, "_", 1) == 0) |
| 303 | /* ignore all internal messages */ |
| 304 | module_send_message(module->base, IMSG_OK, NULL((void *)0)); |
| 305 | else |
| 306 | module_send_message(module->base, IMSG_NG, |
| 307 | "Unknown config parameter `%s'", name); |
| 308 | return; |
| 309 | on_error: |
| 310 | if (groups != NULL((void *)0)) { |
| 311 | for (i = 0; groups[i] != NULL((void *)0); i++) |
| 312 | free(groups[i]); |
| 313 | free(groups); |
| 314 | } |
| 315 | return; |
| 316 | } |
| 317 | |
| 318 | |
| 319 | static void |
| 320 | module_bsdauth_userpass(void *ctx, u_int q_id, const char *user, |
| 321 | const char *pass) |
| 322 | { |
| 323 | struct module_bsdauth *module = ctx; |
| 324 | struct auth_usercheck_args |
| 325 | usercheck; |
| 326 | struct auth_groupcheck_args |
| 327 | groupcheck; |
| 328 | struct iovec iov[4]; |
| 329 | const char *group; |
| 330 | u_int i; |
| 331 | const char *reason; |
| 332 | struct imsg imsg; |
| 333 | ssize_t n; |
| 334 | |
| 335 | memset(&imsg, 0, sizeof(imsg)); |
| 336 | if (pass == NULL((void *)0)) |
| 337 | pass = ""; |
| 338 | |
| 339 | usercheck.userlen = strlen(user) + 1; |
| 340 | usercheck.passlen = strlen(pass) + 1; |
| 341 | iov[0].iov_base = &usercheck; |
| 342 | iov[0].iov_len = sizeof(usercheck); |
| 343 | iov[1].iov_base = (char *)user; |
| 344 | iov[1].iov_len = usercheck.userlen; |
| 345 | iov[2].iov_base = (char *)pass; |
| 346 | iov[2].iov_len = usercheck.passlen; |
| 347 | |
| 348 | imsg_composev(&module->ibuf, IMSG_BSDAUTH_USERCHECK, 0, 0, -1, iov, 3); |
| 349 | imsg_flush(&module->ibuf); |
| 350 | if ((n = imsg_read(&module->ibuf)) == -1 || n == 0) |
| 351 | fatal("imsg_read() failed in module_bsdauth_userpass()"); |
| 352 | if ((n = imsg_get(&module->ibuf, &imsg)) <= 0) |
| 353 | fatal("imsg_get() failed in module_bsdauth_userpass()"); |
| 354 | |
| 355 | if (imsg.hdr.type != IMSG_BSDAUTH_OK) { |
| 356 | reason = "Authentication failed"; |
| 357 | goto auth_ng; |
| 358 | } |
| 359 | if (module->okgroups != NULL((void *)0)) { |
| 360 | reason = "Group restriction is not allowed"; |
| 361 | for (i = 0; module->okgroups[i] != NULL((void *)0); i++) { |
| 362 | group = module->okgroups[i]; |
| 363 | |
| 364 | groupcheck.userlen = strlen(user) + 1; |
| 365 | groupcheck.grouplen = strlen(group) + 1; |
| 366 | iov[0].iov_base = &groupcheck; |
| 367 | iov[0].iov_len = sizeof(groupcheck); |
| 368 | iov[1].iov_base = (char *)user; |
| 369 | iov[1].iov_len = groupcheck.userlen; |
| 370 | iov[2].iov_base = (char *)group; |
| 371 | iov[2].iov_len = groupcheck.grouplen; |
| 372 | imsg_composev(&module->ibuf, IMSG_BSDAUTH_GROUPCHECK, |
| 373 | 0, 0, -1, iov, 3); |
| 374 | imsg_flush(&module->ibuf); |
| 375 | if ((n = imsg_read(&module->ibuf)) == -1 || n == 0) |
| 376 | fatal("imsg_read() failed in " |
| 377 | "module_bsdauth_userpass()"); |
| 378 | if ((n = imsg_get(&module->ibuf, &imsg)) <= 0) |
| 379 | fatal("imsg_get() failed in " |
| 380 | "module_bsdauth_userpass()"); |
| 381 | if (imsg.hdr.type == IMSG_BSDAUTH_OK) |
| 382 | goto group_ok; |
| 383 | } |
| 384 | goto auth_ng; |
| 385 | } |
| 386 | group_ok: |
| 387 | module_userpass_ok(module->base, q_id, "Authentication succeeded"); |
| 388 | imsg_free(&imsg); |
| 389 | return; |
| 390 | auth_ng: |
| 391 | module_userpass_fail(module->base, q_id, reason); |
| 392 | imsg_free(&imsg); |
| 393 | return; |
| 394 | } |
| 395 | |
| 396 | pid_t |
| 397 | start_child(char *argv0, int fd) |
| 398 | { |
| 399 | char *argv[5]; |
| 400 | int argc = 0; |
| 401 | pid_t pid; |
| 402 | |
| 403 | switch (pid = fork()) { |
| 404 | case -1: |
| 405 | fatal("cannot fork"); |
| 406 | case 0: |
| 407 | break; |
| 408 | default: |
| 409 | close(fd); |
| 410 | return (pid); |
| 411 | } |
| 412 | |
| 413 | if (fd != 3) { |
| 414 | if (dup2(fd, 3) == -1) |
| 415 | fatal("cannot setup imsg fd"); |
| 416 | } else if (fcntl(fd, F_SETFD2, 0) == -1) |
| 417 | fatal("cannot setup imsg fd"); |
| 418 | |
| 419 | argv[argc++] = argv0; |
| 420 | argv[argc++] = "-M"; /* main proc */ |
| 421 | execvp(argv0, argv); |
| 422 | fatal("execvp"); |
| 423 | } |
| 424 | |
| 425 | static void |
| 426 | fatal(const char *msg) |
| 427 | { |
| 428 | syslog(LOG_ERR3, "%s: %m", msg); |
| 429 | abort(); |
| 430 | } |