Path: blob/main/documentation/static/source/articles/pam/su.c
18096 views
/*-1* Copyright (c) 2002,2003 Networks Associates Technology, Inc.2* All rights reserved.3*4* This software was developed for the FreeBSD Project by ThinkSec AS and5* Network Associates Laboratories, the Security Research Division of6* Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-80357* ("CBOSS"), as part of the DARPA CHATS research program.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17* 3. The name of the author may not be used to endorse or promote18* products derived from this software without specific prior written19* permission.20*21* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*33* $P4: //depot/projects/openpam/bin/su/su.c#10 $34* $FreeBSD: head/en_US.ISO8859-1/articles/pam/su.c 38826 2012-05-17 19:12:14Z hrs $35*/3637#include <sys/param.h>38#include <sys/wait.h>3940#include <err.h>41#include <pwd.h>42#include <stdio.h>43#include <stdlib.h>44#include <string.h>45#include <syslog.h>46#include <unistd.h>4748#include <security/pam_appl.h>49#include <security/openpam.h> /* for openpam_ttyconv() */5051extern char **environ;5253static pam_handle_t *pamh;54static struct pam_conv pamc;5556static void57usage(void)58{5960fprintf(stderr, "Usage: su [login [args]]\n");61exit(1);62}6364int65main(int argc, char *argv[])66{67char hostname[MAXHOSTNAMELEN];68const char *user, *tty;69char **args, **pam_envlist, **pam_env;70struct passwd *pwd;71int o, pam_err, status;72pid_t pid;7374while ((o = getopt(argc, argv, "h")) != -1)75switch (o) {76case 'h':77default:78usage();79}8081argc -= optind;82argv += optind;8384if (argc > 0) {85user = *argv;86--argc;87++argv;88} else {89user = "root";90}9192/* initialize PAM */93pamc.conv = &openpam_ttyconv;94pam_start("su", user, &pamc, &pamh);9596/* set some items */97gethostname(hostname, sizeof(hostname));98if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)99goto pamerr;100user = getlogin();101if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)102goto pamerr;103tty = ttyname(STDERR_FILENO);104if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)105goto pamerr;106107/* authenticate the applicant */108if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS)109goto pamerr;110if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)111pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);112if (pam_err != PAM_SUCCESS)113goto pamerr;114115/* establish the requested credentials */116if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)117goto pamerr;118119/* authentication succeeded; open a session */120if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)121goto pamerr;122123/* get mapped user name; PAM may have changed it */124pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);125if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)126goto pamerr;127128/* export PAM environment */129if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {130for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {131putenv(*pam_env);132free(*pam_env);133}134free(pam_envlist);135}136137/* build argument list */138if ((args = calloc(argc + 2, sizeof *args)) == NULL) {139warn("calloc()");140goto err;141}142*args = pwd->pw_shell;143memcpy(args + 1, argv, argc * sizeof *args);144145/* fork and exec */146switch ((pid = fork())) {147case -1:148warn("fork()");149goto err;150case 0:151/* child: give up privs and start a shell */152153/* set uid and groups */154if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {155warn("initgroups()");156_exit(1);157}158if (setgid(pwd->pw_gid) == -1) {159warn("setgid()");160_exit(1);161}162if (setuid(pwd->pw_uid) == -1) {163warn("setuid()");164_exit(1);165}166execve(*args, args, environ);167warn("execve()");168_exit(1);169default:170/* parent: wait for child to exit */171waitpid(pid, &status, 0);172173/* close the session and release PAM resources */174pam_err = pam_close_session(pamh, 0);175pam_end(pamh, pam_err);176177exit(WEXITSTATUS(status));178}179180pamerr:181fprintf(stderr, "Sorry\n");182err:183pam_end(pamh, pam_err);184exit(1);185}186187188