10f66f451Sopenharmony_ci/* chsh.c - Change login shell. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2021 Michael Christensen 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/chsh.html 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ciUSE_CHSH(NEWTOY(chsh, "s:", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT)) 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciconfig CHSH 100f66f451Sopenharmony_ci bool "chsh" 110f66f451Sopenharmony_ci default n 120f66f451Sopenharmony_ci help 130f66f451Sopenharmony_ci usage: chsh [-s SHELL] [USER] 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ci Change user's login shell. 160f66f451Sopenharmony_ci 170f66f451Sopenharmony_ci -s Use SHELL instead of prompting 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci Non-root users can only change their own shell to one listed in /etc/shells. 200f66f451Sopenharmony_ci*/ 210f66f451Sopenharmony_ci 220f66f451Sopenharmony_ci#define FOR_chsh 230f66f451Sopenharmony_ci#include "toys.h" 240f66f451Sopenharmony_ci 250f66f451Sopenharmony_ciGLOBALS( 260f66f451Sopenharmony_ci char *s; 270f66f451Sopenharmony_ci) 280f66f451Sopenharmony_ci 290f66f451Sopenharmony_civoid chsh_main() 300f66f451Sopenharmony_ci{ 310f66f451Sopenharmony_ci FILE *file; 320f66f451Sopenharmony_ci char *user, *line, *shell, *encrypted; 330f66f451Sopenharmony_ci struct passwd *passwd_info; 340f66f451Sopenharmony_ci struct spwd *shadow_info; 350f66f451Sopenharmony_ci 360f66f451Sopenharmony_ci // Get uid user information, may be discarded later 370f66f451Sopenharmony_ci 380f66f451Sopenharmony_ci if ((user = *toys.optargs)) { 390f66f451Sopenharmony_ci passwd_info = xgetpwnam(user); 400f66f451Sopenharmony_ci if (geteuid() && strcmp(passwd_info->pw_name, user)) 410f66f451Sopenharmony_ci error_exit("Permission denied\n"); 420f66f451Sopenharmony_ci } else { 430f66f451Sopenharmony_ci passwd_info = xgetpwuid(getuid()); 440f66f451Sopenharmony_ci user = passwd_info->pw_name; 450f66f451Sopenharmony_ci } 460f66f451Sopenharmony_ci 470f66f451Sopenharmony_ci // Get a password, encrypt it, wipe it, and check it 480f66f451Sopenharmony_ci if (mlock(toybuf, sizeof(toybuf))) perror_exit("mlock"); 490f66f451Sopenharmony_ci if (!(shadow_info = getspnam(passwd_info->pw_name))) perror_exit("getspnam"); 500f66f451Sopenharmony_ci if (read_password(toybuf, sizeof(toybuf), "Password: ")) perror_exit("woaj"); //xexit(); 510f66f451Sopenharmony_ci if (!(encrypted = crypt(toybuf, shadow_info->sp_pwdp))) perror_exit("crypt"); 520f66f451Sopenharmony_ci memset(toybuf, 0, sizeof(toybuf)); 530f66f451Sopenharmony_ci munlock(toybuf, sizeof(toybuf)); // prevents memset from "optimizing" away. 540f66f451Sopenharmony_ci if (strcmp(encrypted, shadow_info->sp_pwdp)) perror_exit("Bad password"); 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_ci // Get new shell (either -s or interactive) 570f66f451Sopenharmony_ci file = xfopen("/etc/shells", "r"); 580f66f451Sopenharmony_ci if (toys.optflags) shell = TT.s; 590f66f451Sopenharmony_ci else { 600f66f451Sopenharmony_ci xprintf("Changing the login shell for %s\n" 610f66f451Sopenharmony_ci "Enter the new value, or press ENTER for default\n" 620f66f451Sopenharmony_ci " Login shell [%s]: ", user, passwd_info->pw_shell); 630f66f451Sopenharmony_ci if (!(shell = xgetline(stdin))) xexit(); 640f66f451Sopenharmony_ci } 650f66f451Sopenharmony_ci 660f66f451Sopenharmony_ci // Verify supplied shell in /etc/shells, or get default shell 670f66f451Sopenharmony_ci if (strlen(shell)) 680f66f451Sopenharmony_ci while ((line = xgetline(file)) && strcmp(shell, line)) free(line); 690f66f451Sopenharmony_ci else do line = xgetline(file); while (line && *line != '/'); 700f66f451Sopenharmony_ci if (!line) error_exit("Shell not found in '/etc/shells'"); 710f66f451Sopenharmony_ci 720f66f451Sopenharmony_ci // Update /etc/passwd 730f66f451Sopenharmony_ci passwd_info->pw_shell = line; 740f66f451Sopenharmony_ci if (-1 == update_password("/etc/passwd", user, NULL)) perror_exit("Failed to remove passwd entry"); 750f66f451Sopenharmony_ci file = xfopen("/etc/passwd", "a"); 760f66f451Sopenharmony_ci if (putpwent(passwd_info, file)) perror_exit("putwent"); 770f66f451Sopenharmony_ci} 78