1/*
2 * Copyright (C) 2002-2009 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms of pam_uwtmp, with
5 * or without modification, are permitted provided that the following
6 * conditions are met:
7 *
8 * 1. Redistributions of source code must retain any existing copyright
9 * notice, and this entire permission notice in its entirety,
10 * including the disclaimer of warranties.
11 *
12 * 2. Redistributions in binary form must reproduce all prior and current
13 * copyright notices, this list of conditions, and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 *
17 * 3. The name of any author may not be used to endorse or promote
18 * products derived from this software without their specific prior
19 * written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
29 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 * DAMAGE.
32 */
33
34#include <sys/types.h>
35#include <sys/time.h>
36#include <unistd.h>
37#include <utmpx.h>
38#include <string.h>
39#include <stdlib.h>
40
41#define PAM_SM_SESSION
42#include <security/pam_modules.h>
43#include <security/pam_appl.h>
44#include <security/openpam.h>
45
46#define DATA_NAME "pam_uwtmp.utmpx"
47
48PAM_EXTERN int
49populate_struct(pam_handle_t *pamh, struct utmpx *u)
50{
51	int status;
52	char *tty;
53	char *user;
54	char *remhost;
55
56	if (NULL == u)
57		return PAM_SYSTEM_ERR;
58
59	if (PAM_SUCCESS != (status = pam_get_item(pamh, PAM_USER, (const void **)&user))) {
60		openpam_log(PAM_LOG_DEBUG, "Unable to obtain the username.");
61		return status;
62	}
63	if (NULL != user)
64		strlcpy(u->ut_user, user, sizeof(u->ut_user));
65
66	if (PAM_SUCCESS != (status = pam_get_item(pamh, PAM_TTY, (const void **)&tty))) {
67		openpam_log(PAM_LOG_DEBUG, "Unable to obtain the tty.");
68		return status;
69	}
70	if (NULL == tty) {
71		openpam_log(PAM_LOG_DEBUG, "The tty is NULL.");
72		return PAM_IGNORE;
73	} else
74		strlcpy(u->ut_line, tty, sizeof(u->ut_line));
75
76	if (PAM_SUCCESS != (status = pam_get_item(pamh, PAM_RHOST, (const void **)&remhost))) {
77		openpam_log(PAM_LOG_DEBUG, "Unable to obtain the rhost.");
78		return status;
79	}
80	if (NULL != remhost)
81		strlcpy(u->ut_host, remhost, sizeof(u->ut_host));
82
83	return status;
84}
85
86PAM_EXTERN int
87pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
88{
89	int status;
90	struct utmpx *u = NULL;
91
92	if( (u = calloc(1, sizeof(*u))) == NULL ) {
93		openpam_log(PAM_LOG_ERROR, "Memory allocation error.");
94		return PAM_BUF_ERR;
95	}
96
97	if (PAM_SUCCESS != (status = populate_struct(pamh, u))) {
98		pam_set_data(pamh, DATA_NAME, NULL, NULL);
99		goto err;
100	}
101
102	u->ut_pid = getpid();
103	u->ut_type = UTMPX_AUTOFILL_MASK | USER_PROCESS;
104	gettimeofday(&u->ut_tv, NULL);
105
106	if (PAM_SUCCESS != (status = pam_set_data(pamh, DATA_NAME, u, openpam_free_data))) {
107		openpam_log(PAM_LOG_ERROR, "There was an error setting data in the context.");
108		goto err;
109	}
110
111	if( pututxline(u) == NULL ) {
112		openpam_log(PAM_LOG_ERROR, "Unable to write the utmp record.");
113		status = PAM_SYSTEM_ERR;
114		goto err;
115	}
116
117	return PAM_SUCCESS;
118
119err:
120	free(u);
121	return status;
122}
123
124PAM_EXTERN int
125pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
126{
127	int status;
128	struct utmpx *u = NULL;
129	int free_u = 0;
130
131	status = pam_get_data(pamh, DATA_NAME, (const void **)&u);
132	if( status != PAM_SUCCESS ) {
133		openpam_log(PAM_LOG_DEBUG, "Unable to obtain the tmp record from the context.");
134	}
135
136	if (NULL == u) {
137		if( (u = calloc(1, sizeof(*u))) == NULL ) {
138			openpam_log(PAM_LOG_ERROR, "Memory allocation error.");
139			return PAM_BUF_ERR;
140		}
141		free_u = 1;
142
143		if (PAM_SUCCESS != (status = populate_struct(pamh, u)))
144			goto fin;
145	}
146
147	u->ut_pid = getpid();
148	u->ut_type = UTMPX_AUTOFILL_MASK | DEAD_PROCESS;
149	gettimeofday(&u->ut_tv, NULL);
150
151	if( pututxline(u) == NULL ) {
152		openpam_log(PAM_LOG_ERROR, "Unable to write the utmp record.");
153		status = PAM_SYSTEM_ERR;
154		goto fin;
155	}
156
157	status = PAM_SUCCESS;
158
159fin:
160	if (1 == free_u)
161		free(u);
162	return status;
163}
164