head	1.25;
access;
symbols
	netbsd-11-0-RC4:1.24
	netbsd-11-0-RC3:1.24
	netbsd-11-0-RC2:1.24
	netbsd-11-0-RC1:1.24
	perseant-exfatfs-base-20250801:1.24
	netbsd-11:1.24.0.4
	netbsd-11-base:1.24
	netbsd-10-1-RELEASE:1.23
	perseant-exfatfs-base-20240630:1.24
	perseant-exfatfs:1.24.0.2
	perseant-exfatfs-base:1.24
	netbsd-8-3-RELEASE:1.20.8.2
	netbsd-9-4-RELEASE:1.21
	netbsd-10-0-RELEASE:1.23
	netbsd-10-0-RC6:1.23
	netbsd-10-0-RC5:1.23
	netbsd-10-0-RC4:1.23
	netbsd-10-0-RC3:1.23
	netbsd-10-0-RC2:1.23
	netbsd-10-0-RC1:1.23
	netbsd-10:1.23.0.2
	netbsd-10-base:1.23
	netbsd-9-3-RELEASE:1.21
	cjep_sun2x-base1:1.21
	cjep_sun2x:1.21.0.12
	cjep_sun2x-base:1.21
	cjep_staticlib_x-base1:1.21
	netbsd-9-2-RELEASE:1.21
	cjep_staticlib_x:1.21.0.10
	cjep_staticlib_x-base:1.21
	netbsd-9-1-RELEASE:1.21
	phil-wifi-20200421:1.21
	phil-wifi-20200411:1.21
	is-mlppp:1.21.0.8
	is-mlppp-base:1.21
	phil-wifi-20200406:1.21
	netbsd-8-2-RELEASE:1.20.8.2
	netbsd-9-0-RELEASE:1.21
	netbsd-9-0-RC2:1.21
	netbsd-9-0-RC1:1.21
	phil-wifi-20191119:1.21
	netbsd-9:1.21.0.6
	netbsd-9-base:1.21
	phil-wifi-20190609:1.21
	netbsd-8-1-RELEASE:1.20.8.2
	netbsd-8-1-RC1:1.20.8.2
	pgoyette-compat-merge-20190127:1.21
	pgoyette-compat-20190127:1.21
	pgoyette-compat-20190118:1.21
	pgoyette-compat-1226:1.21
	pgoyette-compat-1126:1.21
	pgoyette-compat-1020:1.21
	pgoyette-compat-0930:1.21
	pgoyette-compat-0906:1.21
	netbsd-7-2-RELEASE:1.19
	pgoyette-compat-0728:1.21
	netbsd-8-0-RELEASE:1.20.8.2
	phil-wifi:1.21.0.4
	phil-wifi-base:1.21
	pgoyette-compat-0625:1.21
	netbsd-8-0-RC2:1.20.8.2
	pgoyette-compat-0521:1.21
	pgoyette-compat-0502:1.21
	pgoyette-compat-0422:1.21
	netbsd-8-0-RC1:1.20.8.2
	pgoyette-compat-0415:1.21
	pgoyette-compat-0407:1.21
	pgoyette-compat-0330:1.21
	pgoyette-compat-0322:1.21
	pgoyette-compat-0315:1.21
	netbsd-7-1-2-RELEASE:1.19
	pgoyette-compat:1.21.0.2
	pgoyette-compat-base:1.21
	netbsd-7-1-1-RELEASE:1.19
	matt-nb8-mediatek:1.20.0.12
	matt-nb8-mediatek-base:1.20
	perseant-stdc-iso10646:1.20.0.10
	perseant-stdc-iso10646-base:1.20
	netbsd-8:1.20.0.8
	netbsd-8-base:1.20
	prg-localcount2-base3:1.20
	prg-localcount2-base2:1.20
	prg-localcount2-base1:1.20
	prg-localcount2:1.20.0.6
	prg-localcount2-base:1.20
	pgoyette-localcount-20170426:1.20
	bouyer-socketcan-base1:1.20
	pgoyette-localcount-20170320:1.20
	netbsd-7-1:1.19.0.12
	netbsd-7-1-RELEASE:1.19
	netbsd-7-1-RC2:1.19
	netbsd-7-nhusb-base-20170116:1.19
	bouyer-socketcan:1.20.0.4
	bouyer-socketcan-base:1.20
	pgoyette-localcount-20170107:1.20
	netbsd-7-1-RC1:1.19
	pgoyette-localcount-20161104:1.20
	netbsd-7-0-2-RELEASE:1.19
	localcount-20160914:1.20
	netbsd-7-nhusb:1.19.0.10
	netbsd-7-nhusb-base:1.19
	pgoyette-localcount-20160806:1.20
	pgoyette-localcount-20160726:1.20
	pgoyette-localcount:1.20.0.2
	pgoyette-localcount-base:1.20
	netbsd-7-0-1-RELEASE:1.19
	netbsd-7-0:1.19.0.8
	netbsd-7-0-RELEASE:1.19
	netbsd-7-0-RC3:1.19
	netbsd-7-0-RC2:1.19
	netbsd-7-0-RC1:1.19
	netbsd-5-2-3-RELEASE:1.15
	netbsd-5-1-5-RELEASE:1.15
	netbsd-6-0-6-RELEASE:1.16
	netbsd-6-1-5-RELEASE:1.16
	netbsd-7:1.19.0.6
	netbsd-7-base:1.19
	yamt-pagecache-base9:1.19
	yamt-pagecache-tag8:1.16.6.1
	netbsd-6-1-4-RELEASE:1.16
	netbsd-6-0-5-RELEASE:1.16
	tls-earlyentropy:1.19.0.4
	tls-earlyentropy-base:1.19
	riastradh-xf86-video-intel-2-7-1-pre-2-21-15:1.19
	riastradh-drm2-base3:1.19
	netbsd-6-1-3-RELEASE:1.16
	netbsd-6-0-4-RELEASE:1.16
	netbsd-5-2-2-RELEASE:1.15
	netbsd-5-1-4-RELEASE:1.15
	netbsd-6-1-2-RELEASE:1.16
	netbsd-6-0-3-RELEASE:1.16
	netbsd-5-2-1-RELEASE:1.15
	netbsd-5-1-3-RELEASE:1.15
	netbsd-6-1-1-RELEASE:1.16
	riastradh-drm2-base2:1.19
	riastradh-drm2-base1:1.19
	riastradh-drm2:1.19.0.2
	riastradh-drm2-base:1.19
	netbsd-6-1:1.16.0.14
	netbsd-6-0-2-RELEASE:1.16
	netbsd-6-1-RELEASE:1.16
	netbsd-6-1-RC4:1.16
	netbsd-6-1-RC3:1.16
	agc-symver:1.17.0.6
	agc-symver-base:1.17
	netbsd-6-1-RC2:1.16
	netbsd-6-1-RC1:1.16
	yamt-pagecache-base8:1.17
	netbsd-5-2:1.15.0.2
	netbsd-6-0-1-RELEASE:1.16
	yamt-pagecache-base7:1.17
	netbsd-5-2-RELEASE:1.15
	netbsd-5-2-RC1:1.15
	matt-nb6-plus-nbase:1.16
	yamt-pagecache-base6:1.17
	netbsd-6-0:1.16.0.12
	netbsd-6-0-RELEASE:1.16
	netbsd-6-0-RC2:1.16
	tls-maxphys:1.17.0.2
	tls-maxphys-base:1.19
	matt-nb6-plus:1.16.0.10
	matt-nb6-plus-base:1.16
	netbsd-6-0-RC1:1.16
	yamt-pagecache-base5:1.17
	yamt-pagecache-base4:1.17
	netbsd-6:1.16.0.8
	netbsd-6-base:1.16
	netbsd-5-1-2-RELEASE:1.15
	netbsd-5-1-1-RELEASE:1.15
	yamt-pagecache-base3:1.16
	yamt-pagecache-base2:1.16
	yamt-pagecache:1.16.0.6
	yamt-pagecache-base:1.16
	cherry-xenmp:1.16.0.4
	cherry-xenmp-base:1.16
	bouyer-quota2-nbase:1.16
	bouyer-quota2:1.16.0.2
	bouyer-quota2-base:1.16
	matt-mips64-premerge-20101231:1.16
	matt-nb5-mips64-premerge-20101231:1.15
	matt-nb5-pq3:1.15.0.14
	matt-nb5-pq3-base:1.15
	netbsd-5-1:1.15.0.12
	netbsd-5-1-RELEASE:1.15
	netbsd-5-1-RC4:1.15
	matt-nb5-mips64-k15:1.15
	netbsd-5-1-RC3:1.15
	netbsd-5-1-RC2:1.15
	netbsd-5-1-RC1:1.15
	netbsd-5-0-2-RELEASE:1.15
	matt-nb5-mips64-premerge-20091211:1.15
	matt-premerge-20091211:1.15
	matt-nb5-mips64-u2-k2-k4-k7-k8-k9:1.15
	matt-nb4-mips64-k7-u2a-k9b:1.15
	matt-nb5-mips64-u1-k1-k5:1.15
	matt-nb5-mips64:1.15.0.10
	netbsd-5-0-1-RELEASE:1.15
	jym-xensuspend-nbase:1.15
	netbsd-5-0:1.15.0.8
	netbsd-5-0-RELEASE:1.15
	netbsd-5-0-RC4:1.15
	netbsd-5-0-RC3:1.15
	netbsd-5-0-RC2:1.15
	jym-xensuspend:1.15.0.6
	jym-xensuspend-base:1.15
	netbsd-5-0-RC1:1.15
	netbsd-5:1.15.0.4
	netbsd-5-base:1.15
	matt-mips64-base2:1.15
	matt-mips64:1.12.0.16
	netbsd-4-0-1-RELEASE:1.12
	wrstuden-revivesa-base-3:1.15
	wrstuden-revivesa-base-2:1.15
	wrstuden-fixsa-newbase:1.12
	wrstuden-revivesa-base-1:1.14
	yamt-pf42-base4:1.14
	yamt-pf42-base3:1.14
	hpcarm-cleanup-nbase:1.14
	yamt-pf42-baseX:1.14
	yamt-pf42-base2:1.14
	wrstuden-revivesa:1.14.0.4
	wrstuden-revivesa-base:1.14
	yamt-pf42:1.14.0.2
	yamt-pf42-base:1.14
	keiichi-mipv6-nbase:1.13
	keiichi-mipv6:1.13.0.4
	keiichi-mipv6-base:1.13
	matt-armv6-nbase:1.13
	matt-armv6-prevmlocking:1.12.12.1
	wrstuden-fixsa-base-1:1.12
	netbsd-4-0:1.12.0.14
	netbsd-4-0-RELEASE:1.12
	cube-autoconf:1.13.0.2
	cube-autoconf-base:1.13
	netbsd-4-0-RC5:1.12
	netbsd-4-0-RC4:1.12
	netbsd-4-0-RC3:1.12
	netbsd-4-0-RC2:1.12
	netbsd-4-0-RC1:1.12
	matt-armv6:1.12.0.12
	matt-armv6-base:1.13
	matt-mips64-base:1.12
	hpcarm-cleanup:1.12.0.10
	hpcarm-cleanup-base:1.13
	netbsd-3-1-1-RELEASE:1.5.2.7
	netbsd-3-0-3-RELEASE:1.5.2.6
	wrstuden-fixsa:1.12.0.8
	wrstuden-fixsa-base:1.12
	abandoned-netbsd-4-base:1.12
	abandoned-netbsd-4:1.12.0.4
	netbsd-3-1:1.5.2.7.0.2
	netbsd-3-1-RELEASE:1.5.2.7
	netbsd-3-0-2-RELEASE:1.5.2.6
	netbsd-3-1-RC4:1.5.2.7
	netbsd-3-1-RC3:1.5.2.7
	netbsd-3-1-RC2:1.5.2.7
	netbsd-3-1-RC1:1.5.2.7
	netbsd-4:1.12.0.6
	netbsd-4-base:1.12
	chap-midi-nbase:1.12
	netbsd-3-0-1-RELEASE:1.5.2.6
	chap-midi:1.12.0.2
	chap-midi-base:1.12
	netbsd-3-0:1.5.2.6.0.2
	netbsd-3-0-RELEASE:1.5.2.6
	netbsd-3-0-RC6:1.5.2.5
	netbsd-3-0-RC5:1.5.2.5
	netbsd-3-0-RC4:1.5.2.5
	netbsd-3-0-RC3:1.5.2.5
	netbsd-3-0-RC2:1.5.2.5
	netbsd-3-0-RC1:1.5.2.5
	netbsd-3:1.5.0.2
	netbsd-3-base:1.5;
locks; strict;
comment	@ * @;


1.25
date	2025.09.07.21.31.20;	author andvar;	state Exp;
branches;
next	1.24;
commitid	56VLkOH4moyFoP9G;

1.24
date	2023.03.24.16.58.24;	author kre;	state Exp;
branches;
next	1.23;
commitid	0OrRxQOtTby1LoiE;

1.23
date	2021.11.27.22.16.42;	author rillig;	state Exp;
branches;
next	1.22;
commitid	ENi90F97EREC0uiD;

1.22
date	2021.09.10.21.52.18;	author rillig;	state Exp;
branches;
next	1.21;
commitid	OPydhl59zcVOns8D;

1.21
date	2018.02.26.00.05.05;	author htodd;	state Exp;
branches;
next	1.20;
commitid	tRxlOxUDAJZCGisA;

1.20
date	2015.08.09.09.39.21;	author shm;	state Exp;
branches
	1.20.8.1;
next	1.19;
commitid	1o5JyRI1FQ4RNzwy;

1.19
date	2013.06.29.05.08.35;	author mlelstv;	state Exp;
branches;
next	1.18;
commitid	NiTDG6tui7jb6tVw;

1.18
date	2013.06.20.20.54.02;	author christos;	state Exp;
branches;
next	1.17;
commitid	jLsvlfUOkFbDCoUw;

1.17
date	2012.03.15.02.02.23;	author joerg;	state Exp;
branches
	1.17.2.1;
next	1.16;

1.16
date	2010.10.02.10.55.36;	author tron;	state Exp;
branches
	1.16.6.1;
next	1.15;

1.15
date	2008.07.21.14.19.26;	author lukem;	state Exp;
branches;
next	1.14;

1.14
date	2008.04.05.15.59.39;	author christos;	state Exp;
branches
	1.14.4.1;
next	1.13;

1.13
date	2007.10.17.21.05.39;	author christos;	state Exp;
branches;
next	1.12;

1.12
date	2006.05.14.21.18.31;	author mlelstv;	state Exp;
branches
	1.12.12.1;
next	1.11;

1.11
date	2005.12.15.14.01.31;	author christos;	state Exp;
branches;
next	1.10;

1.10
date	2005.07.05.20.15.13;	author kleink;	state Exp;
branches;
next	1.9;

1.9
date	2005.04.19.03.17.35;	author christos;	state Exp;
branches;
next	1.8;

1.8
date	2005.04.02.16.12.52;	author he;	state Exp;
branches;
next	1.7;

1.7
date	2005.03.30.01.16.22;	author christos;	state Exp;
branches;
next	1.6;

1.6
date	2005.03.23.20.02.28;	author christos;	state Exp;
branches;
next	1.5;

1.5
date	2005.02.25.21.49.43;	author christos;	state Exp;
branches
	1.5.2.1;
next	1.4;

1.4
date	2005.01.18.21.39.11;	author manu;	state Exp;
branches;
next	1.3;

1.3
date	2005.01.12.01.45.32;	author christos;	state Exp;
branches;
next	1.2;

1.2
date	2005.01.10.23.33.53;	author christos;	state Exp;
branches;
next	1.1;

1.1
date	2005.01.10.03.11.50;	author christos;	state Exp;
branches;
next	;

1.20.8.1
date	2018.02.25.23.51.22;	author htodd;	state Exp;
branches;
next	1.20.8.2;
commitid	siMHKU1rxK7VBisA;

1.20.8.2
date	2018.02.26.00.04.23;	author htodd;	state Exp;
branches;
next	;
commitid	zU5kxsOApsMnGisA;

1.17.2.1
date	2013.06.23.06.29.02;	author tls;	state Exp;
branches;
next	1.17.2.2;
commitid	OnlO1cBgtQRcIHUw;

1.17.2.2
date	2014.08.20.00.05.04;	author tls;	state Exp;
branches;
next	;
commitid	jTnpym9Qu0o4R1Nx;

1.16.6.1
date	2012.04.17.00.09.39;	author yamt;	state Exp;
branches;
next	1.16.6.2;

1.16.6.2
date	2014.05.22.11.42.50;	author yamt;	state Exp;
branches;
next	;
commitid	cG7DCbrDdiE9MwBx;

1.14.4.1
date	2008.09.18.04.29.21;	author wrstuden;	state Exp;
branches;
next	;

1.12.12.1
date	2007.11.06.23.36.16;	author matt;	state Exp;
branches;
next	;

1.5.2.1
date	2005.03.27.16.34.55;	author tron;	state Exp;
branches;
next	1.5.2.2;

1.5.2.2
date	2005.07.06.21.50.22;	author tron;	state Exp;
branches;
next	1.5.2.3;

1.5.2.3
date	2005.07.06.21.51.21;	author tron;	state Exp;
branches;
next	1.5.2.4;

1.5.2.4
date	2005.07.06.21.54.24;	author tron;	state Exp;
branches;
next	1.5.2.5;

1.5.2.5
date	2005.07.09.23.03.05;	author tron;	state Exp;
branches;
next	1.5.2.6;

1.5.2.6
date	2005.12.16.11.57.20;	author tron;	state Exp;
branches;
next	1.5.2.7;

1.5.2.7
date	2006.05.26.16.32.07;	author ghen;	state Exp;
branches;
next	;


desc
@@


1.25
log
@Fix various typos, mainly in comments.
@
text
@/*	$NetBSD: su_pam.c,v 1.24 2023/03/24 16:58:24 kre Exp $	*/

/*
 * Copyright (c) 1988 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@@(#) Copyright (c) 1988\
 The Regents of the University of California.  All rights reserved.");
#endif /* not lint */

#ifndef lint
#if 0
static char sccsid[] = "@@(#)su.c	8.3 (Berkeley) 4/2/94";*/
#else
__RCSID("$NetBSD: su_pam.c,v 1.24 2023/03/24 16:58:24 kre Exp $");
#endif
#endif /* not lint */

#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <grp.h>
#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#include <util.h>
#include <login_cap.h>

#include <security/pam_appl.h>
#include <security/openpam.h>   /* for openpam_ttyconv() */

#ifdef ALLOW_GROUP_CHANGE
#include "grutil.h"
#endif
#include "suutil.h"

static const struct pam_conv pamc = { &openpam_ttyconv, NULL };

#define	ARGSTRX	"-dflm"

#ifdef LOGIN_CAP
#define ARGSTR	ARGSTRX "c:"
#else
#define ARGSTR ARGSTRX
#endif

static void logit(const char *, ...) __printflike(1, 2);

static const char *
safe_pam_strerror(pam_handle_t *pamh, int pam_err) {
	const char *msg;

	if ((msg = pam_strerror(pamh, pam_err)) != NULL)
		return msg;

	static char buf[1024];
	snprintf(buf, sizeof(buf), "Unknown pam error %d", pam_err);
	return buf;
}

int
main(int argc, char **argv)
{
	extern char **environ;
	struct passwd *pwd, pwres;
	char *p;
	uid_t ruid;
	int asme, ch, asthem, fastlogin, prio, gohome;
	u_int setwhat;
	enum { UNSET, YES, NO } iscsh = UNSET;
	const char *user, *shell, *avshell;
	char *username, *class;
	char **np;
	char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
	int pam_err;
	char hostname[MAXHOSTNAMELEN];
	char *tty;
	const char *func;
	const void *newuser;
	login_cap_t *lc;
	pam_handle_t *pamh = NULL;
	char pwbuf[1024];
#ifdef PAM_DEBUG
	extern int _openpam_debug;

	_openpam_debug = 1;
#endif
#ifdef ALLOW_GROUP_CHANGE
	char *gname;
#endif

	(void)setprogname(argv[0]);
	asme = asthem = fastlogin = 0;
	gohome = 1;
	shell = class = NULL;
	while ((ch = getopt(argc, argv, ARGSTR)) != -1)
		switch((char)ch) {
		case 'c':
			class = optarg;
			break;
		case 'd':
			asme = 0;
			asthem = 1;
			gohome = 0;
			break;
		case 'f':
			fastlogin = 1;
			break;
		case '-':
		case 'l':
			asme = 0;
			asthem = 1;
			break;
		case 'm':
			asme = 1;
			asthem = 0;
			break;
		case '?':
		default:
			(void)fprintf(stderr,
#ifdef ALLOW_GROUP_CHANGE
			    "Usage: %s [%s] [login[:group] [shell arguments]]\n",
#else
			    "Usage: %s [%s] [login [shell arguments]]\n",
#endif
			    getprogname(), ARGSTR);
			exit(EXIT_FAILURE);
		}
	argv += optind;

	/* Lower the priority so su runs faster */
	errno = 0;
	prio = getpriority(PRIO_PROCESS, 0);
	if (errno)
		prio = 0;
	if (prio > -2)
		(void)setpriority(PRIO_PROCESS, 0, -2);
	openlog("su", 0, LOG_AUTH);

	/* get current login name and shell */
	ruid = getuid();
	username = getlogin();
	if (username == NULL ||
	    getpwnam_r(username, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
	    pwd == NULL || pwd->pw_uid != ruid) {
		if (getpwuid_r(ruid, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0)
			pwd = NULL;
	}
	if (pwd == NULL)
		errx(EXIT_FAILURE, "who are you?");
	username = estrdup(pwd->pw_name);

	if (asme) {
		if (pwd->pw_shell && *pwd->pw_shell) {
			(void)estrlcpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
			shell = shellbuf;
		} else {
			shell = _PATH_BSHELL;
			iscsh = NO;
		}
	}
	/* get target login information, default to root */
	user = *argv ? *argv : "root";
	np = *argv ? argv : argv - 1;

#ifdef ALLOW_GROUP_CHANGE
	if ((p = strchr(user, ':')) != NULL) {
		*p = '\0';
		gname = ++p;
		if (*gname == '\0')
			errx(EXIT_FAILURE, "missing 'group' after ':'");
	} else
		gname = NULL;

#ifdef ALLOW_EMPTY_USER
	if (user[0] == '\0')
		user = username;
#endif
#endif
	if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
	    pwd == NULL)
		errx(EXIT_FAILURE, "unknown login %s", user);

	/*
	 * PAM initialization
	 */
#define PAM_END(msg) do { func = msg; goto done;} /* NOTREACHED */ while (0)

	if ((pam_err = pam_start("su", user, &pamc, &pamh)) != PAM_SUCCESS) {
		if (pamh != NULL)
			PAM_END("pam_start");
		/* Things went really bad... */
		syslog(LOG_ERR, "pam_start failed: %s",
		    safe_pam_strerror(pamh, pam_err));
		errx(EXIT_FAILURE, "pam_start failed");
	}

#define PAM_END_ITEM(item)	PAM_END("pam_set_item(" # item ")")
#define PAM_SET_ITEM(item, var) 					    \
	if ((pam_err = pam_set_item(pamh, (item), (var))) != PAM_SUCCESS)   \
		PAM_END_ITEM(item)

	/*
	 * Fill hostname, username and tty
	 */
	PAM_SET_ITEM(PAM_RUSER, username);
	if (gethostname(hostname, sizeof(hostname)) != -1)
		PAM_SET_ITEM(PAM_RHOST, hostname);

	if ((tty = ttyname(STDERR_FILENO)) != NULL)
		PAM_SET_ITEM(PAM_TTY, tty);

	/*
	 * Authentication
	 */
	if ((pam_err = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
		syslog(LOG_WARNING, "BAD SU %s to %s%s: %s",
		    username, user, ontty(), safe_pam_strerror(pamh, pam_err));
		(void)pam_end(pamh, pam_err);
		errx(EXIT_FAILURE, "Sorry: %s", safe_pam_strerror(NULL, pam_err));
	}

	/*
	 * Authorization
	 */
	switch(pam_err = pam_acct_mgmt(pamh, 0)) {
	case PAM_NEW_AUTHTOK_REQD:
		pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
		if (pam_err != PAM_SUCCESS)
			PAM_END("pam_chauthok");
		break;
	case PAM_SUCCESS:
		break;
	default:
		PAM_END("pam_acct_mgmt");
		break;
	}

	/*
	 * pam_authenticate might have changed the target user.
	 * refresh pwd and user
	 */
	pam_err = pam_get_item(pamh, PAM_USER, &newuser);
	if (pam_err != PAM_SUCCESS) {
		syslog(LOG_WARNING,
		    "pam_get_item(PAM_USER): %s", safe_pam_strerror(pamh, pam_err));
	} else {
		user = (char *)__UNCONST(newuser);
		if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
		    pwd == NULL) {
			(void)pam_end(pamh, pam_err);
			syslog(LOG_ERR, "unknown login: %s", username);
			errx(EXIT_FAILURE, "unknown login: %s", username);
		}
	}

#define ERRX_PAM_END(args) do {			\
	(void)pam_end(pamh, pam_err);		\
	errx args;				\
} while (0)

#define ERR_PAM_END(args) do {			\
	(void)pam_end(pamh, pam_err);		\
	err args;				\
} while (0)

	/* force the usage of specified class */
	if (class) {
		if (ruid)
			ERRX_PAM_END((EXIT_FAILURE, "Only root may use -c"));

		pwd->pw_class = class;
	}

	if ((lc = login_getclass(pwd->pw_class)) == NULL)
		ERRX_PAM_END((EXIT_FAILURE,
		    "Unknown class %s\n", pwd->pw_class));

	if (asme) {
		/* if asme and non-standard target shell, must be root */
		if (chshell(pwd->pw_shell) == 0 && ruid)
			ERRX_PAM_END((EXIT_FAILURE,
			    "permission denied (shell)."));
	} else if (pwd->pw_shell && *pwd->pw_shell) {
		shell = pwd->pw_shell;
		iscsh = UNSET;
	} else {
		shell = _PATH_BSHELL;
		iscsh = NO;
	}

	if ((p = strrchr(shell, '/')) != NULL)
		avshell = p + 1;
	else
		avshell = shell;

	/* if we're forking a csh, we want to slightly muck the args */
	if (iscsh == UNSET)
		iscsh = strstr(avshell, "csh") ? YES : NO;

	/*
	 * Initialize the supplemental groups before pam gets to them,
	 * so that other pam modules get a chance to add more when
	 * we do setcred. Note, we don't relinquish our set-userid yet
	 */
	/* if we aren't changing users, keep the current group members */
	if (ruid != pwd->pw_uid &&
	    setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) == -1)
		ERR_PAM_END((EXIT_FAILURE, "setting user context"));

#ifdef ALLOW_GROUP_CHANGE
	addgroup(lc, gname, pwd, ruid, "Group Password:");
#endif
	if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
		PAM_END("pam_setcred");

	/*
	 * Manage session.
	 */
	if (asthem) {
		pid_t pid, xpid;
		int status = 1;
		struct sigaction sa, sa_int, sa_pipe, sa_quit;
		int fds[2];

 		if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
			PAM_END("pam_open_session");

		/*
		 * In order to call pam_close_session after the
		 * command terminates, we need to fork.
		 */
		sa.sa_flags = SA_RESTART;
		sa.sa_handler = SIG_IGN;
		(void)sigemptyset(&sa.sa_mask);
		(void)sigaction(SIGINT, &sa, &sa_int);
		(void)sigaction(SIGQUIT, &sa, &sa_quit);
		(void)sigaction(SIGPIPE, &sa, &sa_pipe);
		sa.sa_handler = SIG_DFL;
		(void)sigaction(SIGTSTP, &sa, NULL);
		/*
		 * Use a pipe to guarantee the order of execution of
		 * the parent and the child.
		 */
		if (pipe(fds) == -1) {
			warn("pipe failed");
			goto out;
		}

		switch (pid = fork()) {
		case -1:
			logit("fork failed (%s)", strerror(errno));
			goto out;

		case 0:	/* Child */
			(void)close(fds[1]);
			(void)read(fds[0], &status, 1);
			(void)close(fds[0]);
			(void)sigaction(SIGINT, &sa_int, NULL);
			(void)sigaction(SIGQUIT, &sa_quit, NULL);
			(void)sigaction(SIGPIPE, &sa_pipe, NULL);
			break;

		default:
			sa.sa_handler = SIG_IGN;
			(void)sigaction(SIGTTOU, &sa, NULL);
			(void)close(fds[0]);
			(void)setpgid(pid, pid);
			(void)tcsetpgrp(STDERR_FILENO, pid);
			(void)close(fds[1]);
			(void)sigaction(SIGPIPE, &sa_pipe, NULL);
			/*
			 * Parent: wait for the child to terminate
			 * and call pam_close_session.
			 */
			while ((xpid = waitpid(pid, &status, WUNTRACED))
			    == pid) {
				if (WIFSTOPPED(status)) {
					(void)kill(getpid(), SIGSTOP);
					(void)tcsetpgrp(STDERR_FILENO,
					    getpgid(pid));
					(void)kill(pid, SIGCONT);
					status = 1;
					continue;
				}
				break;
			}

			(void)tcsetpgrp(STDERR_FILENO, getpgid(0));

			if (xpid == -1) {
			    logit("Error waiting for pid %d (%s)", pid,
				strerror(errno));
			} else if (xpid != pid) {
			    /* Can't happen. */
			    logit("Wrong PID: %d != %d", pid, xpid);
			}
out:
			pam_err = pam_setcred(pamh, PAM_DELETE_CRED);
			if (pam_err != PAM_SUCCESS)
				logit("pam_setcred: %s",
				    safe_pam_strerror(pamh, pam_err));
			pam_err = pam_close_session(pamh, 0);
			if (pam_err != PAM_SUCCESS)
				logit("pam_close_session: %s",
				    safe_pam_strerror(pamh, pam_err));
			(void)pam_end(pamh, pam_err);
			exit(WEXITSTATUS(status));
			break;
		}
	}

	/*
	 * The child: starting here, we don't have to care about
	 * handling PAM issues if we exit, the parent will do the
	 * job when we exit.
	 */
#undef PAM_END
#undef ERR_PAM_END
#undef ERRX_PAM_END

	if (!asme) {
		if (asthem) {
			char **pamenv;

			p = getenv("TERM");
			/*
			 * Create an empty environment
			 */
			environ = emalloc(sizeof(char *));
			environ[0] = NULL;

			/*
			 * Add PAM environment, before the LOGIN_CAP stuff:
			 * if the login class is unspecified, we'll get the
			 * same data from PAM, if -c was used, the specified
			 * class must override PAM.
	 		 */
			if ((pamenv = pam_getenvlist(pamh)) != NULL) {
				char **envitem;

				/*
				 * XXX Here FreeBSD filters out
				 * SHELL, LOGNAME, MAIL, CDPATH, IFS, PATH
				 * how could we get untrusted data here?
				 */
				for (envitem = pamenv; *envitem; envitem++) {
					if (putenv(*envitem) == -1)
						free(*envitem);
				}

				free(pamenv);
			}

			if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH |
				LOGIN_SETENV | LOGIN_SETUMASK) == -1)
				err(EXIT_FAILURE, "setting user context");
			if (p)
				(void)setenv("TERM", p, 1);
		}

		if (asthem || pwd->pw_uid) {
			(void)setenv("LOGNAME", pwd->pw_name, 1);
			(void)setenv("USER", pwd->pw_name, 1);
		}
		(void)setenv("HOME", pwd->pw_dir, 1);
		(void)setenv("SHELL", shell, 1);
	}
	(void)setenv("SU_FROM", username, 1);

	if (iscsh == YES) {
		if (fastlogin)
			*np-- = __UNCONST("-f");
		if (asme)
			*np-- = __UNCONST("-m");
	} else {
		if (fastlogin)
			(void)unsetenv("ENV");
	}

	if (asthem) {
		avshellbuf[0] = '-';
		(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
		avshell = avshellbuf;
	} else if (iscsh == YES) {
		/* csh strips the first character... */
		avshellbuf[0] = '_';
		(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
		avshell = avshellbuf;
	}
	*np = __UNCONST(avshell);

	if (ruid != 0)
		syslog(LOG_NOTICE, "%s to %s%s",
		    username, pwd->pw_name, ontty());

	/* Raise our priority back to what we had before */
	(void)setpriority(PRIO_PROCESS, 0, prio);

	/*
	 * Set user context, except for umask, and the stuff
	 * we have done before.
	 */
	setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK |
	    LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP);

	/*
	 * Don't touch resource/priority settings if -m has been used
	 * or -l and -c hasn't, and we're not su'ing to root.
	 */
	if ((asme || (!asthem && class == NULL)) && pwd->pw_uid)
		setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);

	if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) == -1)
		err(EXIT_FAILURE, "setusercontext");

	if (!asme) {
		if (asthem) {
			if (gohome && chdir(pwd->pw_dir) == -1)
				errx(EXIT_FAILURE, "no directory");
		}
	}

	(void)execv(shell, np);
	err(EXIT_FAILURE, "%s", shell);
done:
	logit("%s: %s", func, safe_pam_strerror(pamh, pam_err));
	(void)pam_end(pamh, pam_err);
	return EXIT_FAILURE;
}

static void
logit(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	vwarnx(fmt, ap);
	va_end(ap);
	va_start(ap, fmt);
	vsyslog(LOG_ERR, fmt, ap);
	va_end(ap);
}
@


1.24
log
@
After a ':' (as in login:group or just :group) insist that there
actually be a group name (of some form, don't care what) present.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.23 2021/11/27 22:16:42 rillig Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.23 2021/11/27 22:16:42 rillig Exp $");
d471 1
a471 1
			 * Add PAM environement, before the LOGIN_CAP stuff:
@


1.23
log
@usr.bin: remove unnecessary CONSTCOND, lint no longer needs it

Since 2021-01-31, lint no longer requires a CONSTCOND comment in a
do-while-0 statement since this is a common code pattern, especially in
statement-like macros.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.22 2021/09/10 21:52:18 rillig Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.22 2021/09/10 21:52:18 rillig Exp $");
d207 3
a209 2
	}
	else
@


1.22
log
@usr.bin: remove unnecessary lint comment CONSTCOND

Since 2021-01-31, lint no longer warns about 'do ... while (0)'.

No functional change.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.21 2018/02/26 00:05:05 htodd Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.21 2018/02/26 00:05:05 htodd Exp $");
d296 1
a296 1
} while (/* CONSTCOND */0)
d301 1
a301 1
} while (/* CONSTCOND */0)
@


1.21
log
@Fix typo in comment.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.20 2015/08/09 09:39:21 shm Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.20 2015/08/09 09:39:21 shm Exp $");
d223 1
a223 1
#define PAM_END(msg) do { func = msg; goto done;} /* NOTREACHED */ while (/*CONSTCOND*/0)
@


1.20
log
@Do not use pamh after pam_end. It's cosmetic change since pam_strerror
ignores that parameter.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.19 2013/06/29 05:08:35 mlelstv Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.19 2013/06/29 05:08:35 mlelstv Exp $");
d340 1
a340 1
	 * we do setcred. Note, we don't relinguish our set-userid yet
@


1.20.8.1
log
@Fix typo in comment.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.20 2015/08/09 09:39:21 shm Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.20 2015/08/09 09:39:21 shm Exp $");
d340 1
a340 1
	 * we do setcred. Note, we don't relinquish our set-userid yet
@


1.20.8.2
log
@Undo last commit - wrong tree.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.20.8.1 2018/02/25 23:51:22 htodd Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.20.8.1 2018/02/25 23:51:22 htodd Exp $");
d340 1
a340 1
	 * we do setcred. Note, we don't relinguish our set-userid yet
@


1.19
log
@Change to home directory only after setting the full user context
to avoid issues with NFS or other user-mapped mounts that don't
give root the privilege to chdir there.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.18 2013/06/20 20:54:02 christos Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.18 2013/06/20 20:54:02 christos Exp $");
d256 1
a256 1
		errx(EXIT_FAILURE, "Sorry: %s", safe_pam_strerror(pamh, pam_err));
@


1.18
log
@- don't re-use the va list twice, leads to coredumps.
- introduce and use a "safe" version of pam_strerror(3) that does not return
   NULL
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.17 2012/03/15 02:02:23 joerg Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.17 2012/03/15 02:02:23 joerg Exp $");
a495 2
			if (gohome && chdir(pwd->pw_dir) == -1)
				errx(EXIT_FAILURE, "no directory");
d553 7
@


1.17
log
@Add __printflike attribution to use vprintf and friends with an argument
as format string.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.16 2010/10/02 10:55:36 tron Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.16 2010/10/02 10:55:36 tron Exp $");
d86 12
d230 1
a230 1
		    pam_strerror(pamh, pam_err));
d254 1
a254 1
		    username, user, ontty(), pam_strerror(pamh, pam_err));
d256 1
a256 1
		errx(EXIT_FAILURE, "Sorry: %s", pam_strerror(pamh, pam_err));
d282 1
a282 1
		    "pam_get_item(PAM_USER): %s", pam_strerror(pamh, pam_err));
d438 1
a438 1
				    pam_strerror(pamh, pam_err));
d442 1
a442 1
				    pam_strerror(pamh, pam_err));
d558 1
a558 1
	logit("%s: %s", func, pam_strerror(pamh, pam_err));
d570 2
@


1.17.2.1
log
@resync from head
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
d42 1
a42 1
__RCSID("$NetBSD$");
a85 12
static const char *
safe_pam_strerror(pam_handle_t *pamh, int pam_err) {
	const char *msg;

	if ((msg = pam_strerror(pamh, pam_err)) != NULL)
		return msg;

	static char buf[1024];
	snprintf(buf, sizeof(buf), "Unknown pam error %d", pam_err);
	return buf;
}

d218 1
a218 1
		    safe_pam_strerror(pamh, pam_err));
d242 1
a242 1
		    username, user, ontty(), safe_pam_strerror(pamh, pam_err));
d244 1
a244 1
		errx(EXIT_FAILURE, "Sorry: %s", safe_pam_strerror(pamh, pam_err));
d270 1
a270 1
		    "pam_get_item(PAM_USER): %s", safe_pam_strerror(pamh, pam_err));
d426 1
a426 1
				    safe_pam_strerror(pamh, pam_err));
d430 1
a430 1
				    safe_pam_strerror(pamh, pam_err));
d546 1
a546 1
	logit("%s: %s", func, safe_pam_strerror(pamh, pam_err));
a557 2
	va_end(ap);
	va_start(ap, fmt);
@


1.17.2.2
log
@Rebase to HEAD as of a few days ago.
@
text
@d496 2
a554 7
	if (!asme) {
		if (asthem) {
			if (gohome && chdir(pwd->pw_dir) == -1)
				errx(EXIT_FAILURE, "no directory");
		}
	}

@


1.16
log
@Don't free memory that was succesfully passed to putenv(3) which takes
ownership of the memory.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.15 2008/07/21 14:19:26 lukem Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.15 2008/07/21 14:19:26 lukem Exp $");
d84 1
a84 1
static void logit(const char *, ...);
@


1.16.6.1
log
@sync with head
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
d42 1
a42 1
__RCSID("$NetBSD$");
d84 1
a84 1
static void logit(const char *, ...) __printflike(1, 2);
@


1.16.6.2
log
@sync with head.

for a reference, the tree before this commit was tagged
as yamt-pagecache-tag8.

this commit was splitted into small chunks to avoid
a limitation of cvs.  ("Protocol error: too many arguments")
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.16.6.1 2012/04/17 00:09:39 yamt Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.16.6.1 2012/04/17 00:09:39 yamt Exp $");
a85 12
static const char *
safe_pam_strerror(pam_handle_t *pamh, int pam_err) {
	const char *msg;

	if ((msg = pam_strerror(pamh, pam_err)) != NULL)
		return msg;

	static char buf[1024];
	snprintf(buf, sizeof(buf), "Unknown pam error %d", pam_err);
	return buf;
}

d218 1
a218 1
		    safe_pam_strerror(pamh, pam_err));
d242 1
a242 1
		    username, user, ontty(), safe_pam_strerror(pamh, pam_err));
d244 1
a244 1
		errx(EXIT_FAILURE, "Sorry: %s", safe_pam_strerror(pamh, pam_err));
d270 1
a270 1
		    "pam_get_item(PAM_USER): %s", safe_pam_strerror(pamh, pam_err));
d426 1
a426 1
				    safe_pam_strerror(pamh, pam_err));
d430 1
a430 1
				    safe_pam_strerror(pamh, pam_err));
d484 2
a542 7
	if (!asme) {
		if (asthem) {
			if (gohome && chdir(pwd->pw_dir) == -1)
				errx(EXIT_FAILURE, "no directory");
		}
	}

d546 1
a546 1
	logit("%s: %s", func, safe_pam_strerror(pamh, pam_err));
a557 2
	va_end(ap);
	va_start(ap, fmt);
@


1.15
log
@Remove the \n and tabs from the __COPYRIGHT() strings.
Tweak to use a consistent format.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.14 2008/04/05 15:59:39 christos Exp $	*/
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.14 2008/04/05 15:59:39 christos Exp $");
d472 2
a473 2
					(void)putenv(*envitem);
					free(*envitem);
@


1.14
log
@call setprogname(), from Anon Ymous
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.13 2007/10/17 21:05:39 christos Exp $	*/
d34 2
a35 3
__COPYRIGHT(
    "@@(#) Copyright (c) 1988 The Regents of the University of California.\n\
 All rights reserved.\n");
d42 1
a42 1
__RCSID("$NetBSD: su_pam.c,v 1.13 2007/10/17 21:05:39 christos Exp $");
@


1.14.4.1
log
@Sync with wrstuden-revivesa-base-2.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.14 2008/04/05 15:59:39 christos Exp $	*/
d34 3
a36 2
__COPYRIGHT("@@(#) Copyright (c) 1988\
 The Regents of the University of California.  All rights reserved.");
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.14 2008/04/05 15:59:39 christos Exp $");
@


1.13
log
@From Anon Ymous:
- general cleanup [e-funcs, lint fixes, exit values, more error checking]
- add the ability to change the primary group group as login:group, or :group
  *disabled*, until it is discussed.
- remove krb4 code since there is no more krb4 code in the tree.
- also make the old su behave like the pam su: su to the same user, does
  not ask for a password.
- split out shared code into a separate file.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.12 2006/05/14 21:18:31 mlelstv Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.12 2006/05/14 21:18:31 mlelstv Exp $");
d118 1
@


1.12
log
@restore elevated priority before launching command in
user context. Fixes PR 33479.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.11 2005/12/15 14:01:31 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.11 2005/12/15 14:01:31 christos Exp $");
d64 1
a68 2
 
static const struct pam_conv pamc = { &openpam_ttyconv, NULL };
d70 4
a73 3
static void logit(const char *, ...);
static int chshell(const char *);
static char *ontty(void);
d75 1
a75 1
int main(int, char **);
d85 2
d94 2
a95 1
	int asme, ch, asthem, fastlogin, prio, gohome, setwhat;
d97 3
a99 2
	char *user, *shell, *avshell, *username, **np;
	char *class;
d114 3
d146 3
d150 1
d168 1
a168 1
	if (username == NULL || 
d176 1
a176 2
	if ((username = strdup(pwd->pw_name)) == NULL)
		err(EXIT_FAILURE, "strdup");
d180 1
a180 1
			strlcpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
d191 13
d211 1
a211 1
#define PAM_END(msg) do { func = msg; goto done; } while (/*CONSTCOND*/0)
d237 2
a238 2
	/* 
	 * Authentication 
d243 1
a243 1
		pam_end(pamh, pam_err);
d264 1
a264 1
	 * pam_authenticate might have changed the target user. 
d272 1
a272 1
		user = (char *)newuser;
d275 1
a275 1
			pam_end(pamh, pam_err);
d282 1
a282 1
	pam_end(pamh, pam_err);			\
d284 1
a284 1
} while (/* CONSTOCOND */0)
d287 1
a287 1
	pam_end(pamh, pam_err);			\
d289 2
a290 2
} while (/* CONSTOCOND */0)
	
d293 1
a293 1
		if (ruid) 
d305 1
a305 1
		if (!chshell(pwd->pw_shell) && ruid)
d330 3
a332 1
	if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0)   
d335 3
d342 1
a342 1
	 * Manage session. 
d355 1
a355 1
		 * command terminates, we need to fork. 
d359 1
a359 1
		sigemptyset(&sa.sa_mask);
d373 1
a373 1
		
d425 1
a425 1
				logit("pam_setcred: %s", 
d429 1
a429 1
				logit("pam_close_session: %s", 
d431 1
a431 1
			pam_end(pamh, pam_err);
d433 1
a433 1
			break;	
d437 1
a437 1
	/* 
d439 1
a439 1
	 * handling PAM issues if we exit, the parent will do the 
d451 2
a452 2
			/* 
			 * Create an empty environment 
d454 1
a454 2
			if ((environ = malloc(sizeof(char *))) == NULL)
				err(EXIT_FAILURE, NULL);
d457 1
a457 1
			/* 
d466 2
a467 2
				/* 
				 * XXX Here FreeBSD filters out 
d472 2
a473 2
					putenv(*envitem);
					free(*envitem); 
d479 2
a480 2
			if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH|
			    LOGIN_SETENV|LOGIN_SETUMASK))
d484 1
a484 1
			if (gohome && chdir(pwd->pw_dir) < 0)
d486 1
a486 1
		} 
d499 1
a499 1
			*np-- = "-f";
d501 1
a501 1
			*np-- = "-m";
d504 1
a504 1
			unsetenv("ENV");
d509 1
a509 1
		(void)strlcpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 1);
d514 1
a514 1
		(void)strlcpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 1);
d517 1
a517 1
	*np = avshell;
d530 2
a531 2
	setwhat = LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETUMASK|
	    LOGIN_SETLOGIN|LOGIN_SETPATH|LOGIN_SETGROUP);
d538 1
a538 1
		setwhat &= ~(LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
d547 1
a547 1
	pam_end(pamh, pam_err);
a560 25


static int
chshell(const char *sh)
{
	const char *cp;

	setusershell();
	while ((cp = getusershell()) != NULL)
		if (!strcmp(cp, sh))
			return 1;
	return 0;
}

static char *
ontty(void)
{
	char *p;
	static char buf[MAXPATHLEN + 4];

	buf[0] = 0;
	if ((p = ttyname(STDERR_FILENO)) != NULL)
		(void)snprintf(buf, sizeof buf, " on %s", p);
	return buf;
}
@


1.12.12.1
log
@sync with HEAD
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.13 2007/10/17 21:05:39 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.13 2007/10/17 21:05:39 christos Exp $");
a63 1
#include <util.h>
d68 2
d71 3
a73 4
#ifdef ALLOW_GROUP_CHANGE
#include "grutil.h"
#endif
#include "suutil.h"
d75 1
a75 1
static const struct pam_conv pamc = { &openpam_ttyconv, NULL };
a84 2
static void logit(const char *, ...);

d92 1
a92 2
	int asme, ch, asthem, fastlogin, prio, gohome;
	u_int setwhat;
d94 2
a95 3
	const char *user, *shell, *avshell;
	char *username, *class;
	char **np;
a109 3
#ifdef ALLOW_GROUP_CHANGE
	char *gname;
#endif
a138 3
#ifdef ALLOW_GROUP_CHANGE
			    "Usage: %s [%s] [login[:group] [shell arguments]]\n",
#else
a139 1
#endif
d157 1
a157 1
	if (username == NULL ||
d165 2
a166 1
	username = estrdup(pwd->pw_name);
d170 1
a170 1
			(void)estrlcpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
a180 13
#ifdef ALLOW_GROUP_CHANGE
	if ((p = strchr(user, ':')) != NULL) {
		*p = '\0';
		gname = ++p;
	}
	else
		gname = NULL;

#ifdef ALLOW_EMPTY_USER
	if (user[0] == '\0')
		user = username;
#endif
#endif
d188 1
a188 1
#define PAM_END(msg) do { func = msg; goto done;} /* NOTREACHED */ while (/*CONSTCOND*/0)
d214 2
a215 2
	/*
	 * Authentication
d220 1
a220 1
		(void)pam_end(pamh, pam_err);
d241 1
a241 1
	 * pam_authenticate might have changed the target user.
d249 1
a249 1
		user = (char *)__UNCONST(newuser);
d252 1
a252 1
			(void)pam_end(pamh, pam_err);
d259 1
a259 1
	(void)pam_end(pamh, pam_err);		\
d261 1
a261 1
} while (/* CONSTCOND */0)
d264 1
a264 1
	(void)pam_end(pamh, pam_err);		\
d266 2
a267 2
} while (/* CONSTCOND */0)

d270 1
a270 1
		if (ruid)
d282 1
a282 1
		if (chshell(pwd->pw_shell) == 0 && ruid)
d307 1
a307 3
	/* if we aren't changing users, keep the current group members */
	if (ruid != pwd->pw_uid &&
	    setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) == -1)
a309 3
#ifdef ALLOW_GROUP_CHANGE
	addgroup(lc, gname, pwd, ruid, "Group Password:");
#endif
d314 1
a314 1
	 * Manage session.
d327 1
a327 1
		 * command terminates, we need to fork.
d331 1
a331 1
		(void)sigemptyset(&sa.sa_mask);
d345 1
a345 1

d397 1
a397 1
				logit("pam_setcred: %s",
d401 1
a401 1
				logit("pam_close_session: %s",
d403 1
a403 1
			(void)pam_end(pamh, pam_err);
d405 1
a405 1
			break;
d409 1
a409 1
	/*
d411 1
a411 1
	 * handling PAM issues if we exit, the parent will do the
d423 2
a424 2
			/*
			 * Create an empty environment
d426 2
a427 1
			environ = emalloc(sizeof(char *));
d430 1
a430 1
			/*
d439 2
a440 2
				/*
				 * XXX Here FreeBSD filters out
d445 2
a446 2
					(void)putenv(*envitem);
					free(*envitem);
d452 2
a453 2
			if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH |
				LOGIN_SETENV | LOGIN_SETUMASK) == -1)
d457 1
a457 1
			if (gohome && chdir(pwd->pw_dir) == -1)
d459 1
a459 1
		}
d472 1
a472 1
			*np-- = __UNCONST("-f");
d474 1
a474 1
			*np-- = __UNCONST("-m");
d477 1
a477 1
			(void)unsetenv("ENV");
d482 1
a482 1
		(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
d487 1
a487 1
		(void)estrlcpy(avshellbuf + 1, avshell, sizeof(avshellbuf) - 1);
d490 1
a490 1
	*np = __UNCONST(avshell);
d503 2
a504 2
	setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK |
	    LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP);
d511 1
a511 1
		setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
d520 1
a520 1
	(void)pam_end(pamh, pam_err);
d534 25
@


1.11
log
@PR/32307: Jason V. Miller: su fails to set umask correctly when using pam
and simulating a full login (-, -d, -l)
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.10 2005/07/05 20:15:13 kleink Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.10 2005/07/05 20:15:13 kleink Exp $");
d496 3
@


1.10
log
@Set LOGNAME in the new environment (in addition to USER);
fixes PR bin/30670 from Pavel Cahyna.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.9 2005/04/19 03:17:35 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.9 2005/04/19 03:17:35 christos Exp $");
d452 2
a453 1
			if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH))
@


1.9
log
@check for pwd != NULL
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.8 2005/04/02 16:12:52 he Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.8 2005/04/02 16:12:52 he Exp $");
d460 2
a461 1
		if (asthem || pwd->pw_uid)
d463 1
@


1.8
log
@Put declaration of pwbuf[] back before any code, so this compiles with
older versions of gcc again.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.7 2005/03/30 01:16:22 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.7 2005/03/30 01:16:22 christos Exp $");
d159 1
a159 1
	    pwd->pw_uid != ruid) {
d181 2
a182 1
	if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0)
d250 2
a251 1
		if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0) {
@


1.7
log
@- Use the getpw*_r methods.
- KNF.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.6 2005/03/23 20:02:28 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.6 2005/03/23 20:02:28 christos Exp $");
d104 1
d107 1
a109 1
	char pwbuf[1024];
@


1.6
log
@Deal with signals and process groups (from FreeBSD)
Fixes issues with kill -STOP $$ in the su'd shell, and setting up signals
for the child process properly.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.5 2005/02/25 21:49:43 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.5 2005/02/25 21:49:43 christos Exp $");
d89 1
a89 1
	struct passwd *pwd;
d108 1
d140 1
a140 1
			exit(1);
d156 6
a161 3
	if (username == NULL || (pwd = getpwnam(username)) == NULL ||
	    pwd->pw_uid != ruid)
		pwd = getpwuid(ruid);
d163 1
a163 1
		errx(1, "who are you?");
d165 1
a165 2
		err(1, "strdup");

d180 2
a181 2
	if ((pwd = getpwnam(user)) == NULL)
		errx(1, "unknown login %s", user);
d194 1
a194 1
		errx(1, "pam_start failed");
d219 1
a219 1
		errx(1, "Sorry: %s", pam_strerror(pamh, pam_err));
d248 1
a248 1
		if ((pwd = getpwnam(user)) == NULL) {	
d251 1
a251 1
			errx(1, "unknown login: %s", username);
d268 1
a268 1
			ERRX_PAM_END((1, "Only root may use -c"));
d274 2
a275 1
		ERRX_PAM_END((1, "Unknown class %s\n", pwd->pw_class));
d280 2
a281 1
			ERRX_PAM_END((1,"permission denied (shell)."));
d305 1
a305 1
		ERR_PAM_END((1, "setting user context"));
d424 1
a424 1
				err(1, NULL);
d450 1
a450 1
				err(1, "setting user context");
d454 1
a454 1
				errx(1, "no directory");
d505 1
a505 1
		err(1, "setusercontext");
d508 1
a508 1
	err(1, "%s", shell);
d512 1
a512 1
	return 1;
@


1.5
log
@Don't wait for any process, just our child. pam sessions can fork other
processes (such as the ssh pam agent handler) and the wrong process ends
up reaped, wreaking havoc.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.4 2005/01/18 21:39:11 manu Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.4 2005/01/18 21:39:11 manu Exp $");
d56 1
d71 1
d310 3
a312 3
		void *oint;
		void *oabrt;
		int status;
a319 6
		 * Make sure signals cannot kill the parent.
		 * This is copied from crontab(8), which has to
		 * cope with a similar situation. XXX FreeBSD 
		 * has a much more complicated code (CVS logs 
		 * tell about workaround in libpthread, but we 
		 * might miss useful stuff)
d321 16
a336 2
		oint = signal(SIGINT, SIG_IGN);
		oabrt = signal(SIGABRT, SIG_IGN);
d340 2
a341 9
			pam_err = pam_close_session(pamh, 0);
			if (pam_err != PAM_SUCCESS) {
				syslog(LOG_ERR, "pam_close_session: %s", 
				    pam_strerror(pamh, pam_err));
				warnx("pam_close_session: %s", 
				    pam_strerror(pamh, pam_err));
			}
			ERR_PAM_END((1, "fork"));
			break;
d344 6
d353 7
d364 9
a372 16
			if ((xpid = waitpid(pid, &status, 0)) != pid) {
				pam_err = pam_close_session(pamh, 0);
				if (pam_err != PAM_SUCCESS) {
					syslog(LOG_ERR, 
					    "pam_close_session: %s", 
					    pam_strerror(pamh, pam_err));
					warnx("pam_close_session: %s", 
					    pam_strerror(pamh, pam_err));
				}
				if (xpid == -1) {
					ERR_PAM_END((1, 
					    "error waiting for pid %d", pid));
				} else {
					// Can't happen.
					ERRX_PAM_END((1, 
					    "wrong PID: %d != %d", pid, xpid));
d374 1
a375 3
		
			(void)signal(SIGINT, oint);
			(void)signal(SIGABRT, oabrt);
d377 11
a387 1
 			pam_err = pam_close_session(pamh, 0);
d389 8
a396 4
				PAM_END("pam_open_session");

			pam_end(pamh, PAM_SUCCESS);
			exit(0);
d505 1
a505 2
	syslog(LOG_ERR, "%s: %s", func, pam_strerror(pamh, pam_err));
	warnx("%s: %s", func, pam_strerror(pamh, pam_err));
d510 12
@


1.5.2.1
log
@Pull up revision 1.6 (requested by christos in ticket #65):
Deal with signals and process groups (from FreeBSD)
Fixes issues with kill -STOP $$ in the su'd shell, and setting up signals
for the child process properly.
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
d43 1
a43 1
__RCSID("$NetBSD$");
a55 1
#include <signal.h>
a69 1
static void logit(const char *, ...);
d308 3
a310 3
		int status = 1;
		struct sigaction sa, sa_int, sa_pipe, sa_quit;
		int fds[2];
d318 6
d325 2
a326 16
		sa.sa_flags = SA_RESTART;
		sa.sa_handler = SIG_IGN;
		sigemptyset(&sa.sa_mask);
		(void)sigaction(SIGINT, &sa, &sa_int);
		(void)sigaction(SIGQUIT, &sa, &sa_quit);
		(void)sigaction(SIGPIPE, &sa, &sa_pipe);
		sa.sa_handler = SIG_DFL;
		(void)sigaction(SIGTSTP, &sa, NULL);
		/*
		 * Use a pipe to guarantee the order of execution of
		 * the parent and the child.
		 */
		if (pipe(fds) == -1) {
			warn("pipe failed");
			goto out;
		}
d330 9
a338 2
			logit("fork failed (%s)", strerror(errno));
			goto out;
a340 6
			(void)close(fds[1]);
			(void)read(fds[0], &status, 1);
			(void)close(fds[0]);
			(void)sigaction(SIGINT, &sa_int, NULL);
			(void)sigaction(SIGQUIT, &sa_quit, NULL);
			(void)sigaction(SIGPIPE, &sa_pipe, NULL);
a343 7
			sa.sa_handler = SIG_IGN;
			(void)sigaction(SIGTTOU, &sa, NULL);
			(void)close(fds[0]);
			(void)setpgid(pid, pid);
			(void)tcsetpgrp(STDERR_FILENO, pid);
			(void)close(fds[1]);
			(void)sigaction(SIGPIPE, &sa_pipe, NULL);
d348 16
a363 9
			while ((xpid = waitpid(pid, &status, WUNTRACED))
			    == pid) {
				if (WIFSTOPPED(status)) {
					(void)kill(getpid(), SIGSTOP);
					(void)tcsetpgrp(STDERR_FILENO,
					    getpgid(pid));
					(void)kill(pid, SIGCONT);
					status = 1;
					continue;
a364 1
				break;
d366 3
d370 3
a372 1
			(void)tcsetpgrp(STDERR_FILENO, getpgid(0));
d374 2
a375 18
			if (xpid == -1) {
			    logit("Error waiting for pid %d (%s)", pid,
				strerror(errno));
			} else if (xpid != pid) {
			    /* Can't happen. */
			    logit("Wrong PID: %d != %d", pid, xpid);
			}
out:
			pam_err = pam_setcred(pamh, PAM_DELETE_CRED);
			if (pam_err != PAM_SUCCESS)
				logit("pam_setcred: %s", 
				    pam_strerror(pamh, pam_err));
			pam_err = pam_close_session(pamh, 0);
			if (pam_err != PAM_SUCCESS)
				logit("pam_close_session: %s", 
				    pam_strerror(pamh, pam_err));
			pam_end(pamh, pam_err);
			exit(WEXITSTATUS(status));
d484 2
a485 1
	logit("%s: %s", func, pam_strerror(pamh, pam_err));
a489 12
static void
logit(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	vwarnx(fmt, ap);
	vsyslog(LOG_ERR, fmt, ap);
	va_end(ap);
}


@


1.5.2.2
log
@Pull up revision 1.7 (requested by lukem in ticket #530):
- Use the getpw*_r methods.
- KNF.
@
text
@d89 1
a89 1
	struct passwd *pwd, pwres;
a107 1
	char pwbuf[1024];
d139 1
a139 1
			exit(EXIT_FAILURE);
d155 3
a157 6
	if (username == NULL || 
	    getpwnam_r(username, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
	    pwd->pw_uid != ruid) {
		if (getpwuid_r(ruid, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0)
			pwd = NULL;
	}
d159 1
a159 1
		errx(EXIT_FAILURE, "who are you?");
d161 2
a162 1
		err(EXIT_FAILURE, "strdup");
d177 2
a178 2
	if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0)
		errx(EXIT_FAILURE, "unknown login %s", user);
d191 1
a191 1
		errx(EXIT_FAILURE, "pam_start failed");
d216 1
a216 1
		errx(EXIT_FAILURE, "Sorry: %s", pam_strerror(pamh, pam_err));
d245 1
a245 1
		if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0) {
d248 1
a248 1
			errx(EXIT_FAILURE, "unknown login: %s", username);
d265 1
a265 1
			ERRX_PAM_END((EXIT_FAILURE, "Only root may use -c"));
d271 1
a271 2
		ERRX_PAM_END((EXIT_FAILURE,
		    "Unknown class %s\n", pwd->pw_class));
d276 1
a276 2
			ERRX_PAM_END((EXIT_FAILURE,
			    "permission denied (shell)."));
d300 1
a300 1
		ERR_PAM_END((EXIT_FAILURE, "setting user context"));
d419 1
a419 1
				err(EXIT_FAILURE, NULL);
d445 1
a445 1
				err(EXIT_FAILURE, "setting user context");
d449 1
a449 1
				errx(EXIT_FAILURE, "no directory");
d500 1
a500 1
		err(EXIT_FAILURE, "setusercontext");
d503 1
a503 1
	err(EXIT_FAILURE, "%s", shell);
d507 1
a507 1
	return EXIT_FAILURE;
@


1.5.2.3
log
@Pull up revision 1.8 (requested by lukem in ticket #530):
Put declaration of pwbuf[] back before any code, so this compiles with
older versions of gcc again.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.5.2.2 2005/07/06 21:50:22 tron Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.5.2.2 2005/07/06 21:50:22 tron Exp $");
a103 1
	char pwbuf[1024];
a105 1

d108 1
@


1.5.2.4
log
@Pull up revision 1.9 (requested by lukem in ticket #530):
check for pwd != NULL
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.5.2.3 2005/07/06 21:51:21 tron Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.5.2.3 2005/07/06 21:51:21 tron Exp $");
d159 1
a159 1
	    pwd == NULL || pwd->pw_uid != ruid) {
d181 1
a181 2
	if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
	    pwd == NULL)
d249 1
a249 2
		if (getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
		    pwd == NULL) {
@


1.5.2.5
log
@Pull up revision 1.10 (requested by kleink in ticket #551):
Set LOGNAME in the new environment (in addition to USER);
fixes PR bin/30670 from Pavel Cahyna.
@
text
@d1 1
a1 1
/*	$NetBSD$	*/
d43 1
a43 1
__RCSID("$NetBSD$");
d460 1
a460 2
		if (asthem || pwd->pw_uid) {
			(void)setenv("LOGNAME", pwd->pw_name, 1);
a461 1
		}
@


1.5.2.6
log
@Pull up following revision(s) (requested by hubertf in ticket #1061):
	usr.bin/su/su_pam.c: revision 1.11
PR/32307: Jason V. Miller: su fails to set umask correctly when using pam
and simulating a full login (-, -d, -l)
@
text
@d452 1
a452 2
			if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH|
			    LOGIN_SETENV|LOGIN_SETUMASK))
@


1.5.2.7
log
@Pull up following revision(s) (requested by mlelstv in ticket #1343):
	usr.bin/su/su_pam.c: revision 1.12
restore elevated priority before launching command in
user context. Fixes PR 33479.
@
text
@a495 3
	/* Raise our priority back to what we had before */
	(void)setpriority(PRIO_PROCESS, 0, prio);

@


1.4
log
@Remove unneeded \ at the end of line, style
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.3 2005/01/12 01:45:32 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.3 2005/01/12 01:45:32 christos Exp $");
d348 1
a348 1
			if ((xpid = wait(&status)) != pid) {
d357 8
a364 2
				ERRX_PAM_END((1, 
				    "wrong PID: %d != %d", pid, xpid));
@


1.3
log
@Always print pam error in messages
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.2 2005/01/10 23:33:53 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.2 2005/01/10 23:33:53 christos Exp $");
d193 2
a194 2
#define PAM_SET_ITEM(item, var) \
	if ((pam_err = pam_set_item(pamh, (item), (var))) != PAM_SUCCESS) \
d478 3
a480 3
	syslog(LOG_ERR, "%s: %s", func, pam_strerror(pamh, pam_err));   \
	warnx("%s: %s", func, pam_strerror(pamh, pam_err));             \
	pam_end(pamh, pam_err);                                         \
@


1.2
log
@- make LOGIN_CAP mandatory
- eliminate global pamh
- use setusercontext() properly (ideas borrowed from FreeBSD)
- remove stray debugging.

This now works.
@
text
@d1 1
a1 1
/*	$NetBSD: su_pam.c,v 1.1 2005/01/10 03:11:50 christos Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su_pam.c,v 1.1 2005/01/10 03:11:50 christos Exp $");
d187 2
a188 1
		syslog(LOG_ERR, "pam_start failed");
d211 2
a212 2
		syslog(LOG_WARNING, "BAD SU %s to %s%s",
		    username, user, ontty());
d214 1
a214 1
		errx(1, "Sorry");
@


1.1
log
@Restore su.c to version 1.58, plus minor prototyping. Split pam
into su_pam.c, and turn it off by default in the Makefile until it
is tested and actually works. The current pam version does not set ruid
properly anymore.
@
text
@d1 1
a1 1
/*	$NetBSD: su.c,v 1.63 2005/01/09 21:32:38 manu Exp $	*/
d43 1
a43 1
__RCSID("$NetBSD: su.c,v 1.63 2005/01/09 21:32:38 manu Exp $");
a62 2

#ifdef LOGIN_CAP
a63 1
#endif
d68 1
a69 2
static pam_handle_t *pamh = NULL;
static const struct pam_conv pamc = { &openpam_ttyconv, NULL };
d90 1
a90 1
	int asme, ch, asthem, fastlogin, prio, gohome;
a99 1
#ifdef LOGIN_CAP
d101 1
a101 1
#endif
a111 1
#ifdef LOGIN_CAP
a114 1
#endif
a258 1
#ifdef LOGIN_CAP
d266 1
a268 1
#endif
d291 4
a294 6
	/* 
	 * Set permissions. We change the user credentials (UID) here 
	 * XXX PAM should come before LOGIN_CAP so that the class
	 * specified through -c can override PAM. But as we might drop
	 * root UID on both operations, it is not possible to do that.
	 * If a login class was specified, skip PAM. 
d296 5
a300 14
#ifdef LOGIN_CAP
	if (class) {
		if (setusercontext(lc, pwd, pwd->pw_uid,
		    (asthem ? (LOGIN_SETPRIORITY | LOGIN_SETUMASK) : 0) |
		    LOGIN_SETRESOURCES | LOGIN_SETGROUP | LOGIN_SETUSER))
			ERR_PAM_END((1, "setting user context"));
		printf("%d %d\n", asthem, pwd->pw_uid);
	} else 
#endif
	{
		pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED);
		if (pam_err != PAM_SUCCESS)
			PAM_END("pam_setcred");
	}
a415 1
#ifdef LOGIN_CAP
a417 3
#else
			(void)setenv("PATH", _PATH_DEFPATH, 1);
#endif
d457 16
a472 2
	/* Raise our priority back to what we had before */
	(void)setpriority(PRIO_PROCESS, 0, prio);
a473 1
	printf("%d %d\n", geteuid(), getuid());
@
