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.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 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 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; 103 104 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNSPEC, 105 pairsock) == -1) 106 err(EXIT_FAILURE, "socketpair"); 107 108 openlog(NULL, LOG_PID, LOG_DAEMON); 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) == -1) 119 err(EXIT_FAILURE, "pledge"); 120 121 for (;;) { 122 if ((n = imsg_read(&ibuf)) <= 0 && errno != EAGAIN) 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_SIZE; 130 switch (imsg.hdr.type) { 131 case IMSG_BSDAUTH_USERCHECK: 132 { 133 char *user, *pass; 134 bool authok = false; 135 struct auth_usercheck_args 136 *args; 137 138 if (datalen < sizeof( 139 struct auth_usercheck_args)) { 140 syslog(LOG_ERR, "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_ERR, "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, NULL, pass)) 156 authok = true; 157 explicit_bzero(pass, args->passlen); 158 159 imsg_compose(&ibuf, (authok) 160 ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG, 161 0, 0, -1, NULL, 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 group_ok = false; 172 struct auth_groupcheck_args 173 *args; 174 175 if (datalen < sizeof( 176 struct auth_groupcheck_args)) { 177 syslog(LOG_ERR, "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_ERR, "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) 195 goto invalid; 196 if (getgrnam_r(group, &gr0, g_buf, 197 sizeof(g_buf), &gr) == -1 || gr == NULL) 198 goto invalid; 199 200 if (gr->gr_gid == pw->pw_gid) { 201 group_ok = true; 202 goto invalid; 203 } 204 for (i = 0; gr->gr_mem[i] != NULL; i++) { 205 if (strcmp(gr->gr_mem[i], pw->pw_name) 206 == 0) { 207 group_ok = true; 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, 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 != EINTR) 229 break; 230 } 231 exit(WEXITSTATUS(status)); 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, LOG_PID, LOG_DAEMON); 245 memset(&module_bsdauth, 0, sizeof(module_bsdauth)); 246 if ((module_bsdauth.base = module_create(STDIN_FILENO, &module_bsdauth, 247 &module_bsdauth_handlers)) == NULL) 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) == -1) 256 err(EXIT_FAILURE, "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; i++) 266 free(module_bsdauth.okgroups[i]); 267 } 268 free(module_bsdauth.okgroups); 269 270 exit(EXIT_SUCCESS); 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; 280 281 if (strcmp(name, "restrict-group") == 0) { 282 if (module->okgroups != NULL) { 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) { 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) { 294 module_send_message(module->base, 295 IMSG_NG, "Out of memory"); 296 goto on_error; 297 } 298 } 299 groups[i] = NULL; 300 module->okgroups = groups; 301 module_send_message(module->base, IMSG_OK, NULL); 302 } else if (strncmp(name, "_", 1) == 0) 303 /* ignore all internal messages */ 304 module_send_message(module->base, IMSG_OK, NULL); 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) { 311 for (i = 0; groups[i] != NULL; 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) 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) { 360 reason = "Group restriction is not allowed"; 361 for (i = 0; module->okgroups[i] != NULL; 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_SETFD, 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_ERR, "%s: %m", msg); 429 abort(); 430 } 431