forked from jakevdp/shim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pam.c
206 lines (195 loc) · 5.24 KB
/
pam.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
* Portions of this file are adapted from the Pam.cpp source file
* copyrighted by RStudio, Inc. licensed under the AGPL 3. The
* original copyright statement follows.
*
* Copyright (C) 2009-12 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
* Additional portions based on Per-Aake Larson's Dynamic Hashing algorithms.
* BIT 18 (1978). and public domain example by [email protected].
*/
#include <security/pam_appl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "pam.h"
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
/* A conversation function for PAM to non-interactively supply username
* and password.
*/
int
conv (int num_msg,
const struct pam_message **msg,
struct pam_response **resp, void *appdata_ptr)
{
int i;
/* Note: The PAM caller will free response. */
*resp =
(struct pam_response *) malloc (sizeof (struct pam_response) * num_msg);
if (!*resp)
return PAM_BUF_ERR;
memset (*resp, 0, sizeof (struct pam_response) * num_msg);
for (i = 0; i < num_msg; i++)
{
const struct pam_message *input = msg[i];
switch (input->msg_style)
{
case PAM_PROMPT_ECHO_OFF:
{
resp[i]->resp_retcode = 0;
/* Note: The PAM caller will free resp[i]->resp here or below. */
resp[i]->resp = strdup ((char *) appdata_ptr);
break;
}
case PAM_TEXT_INFO:
{
resp[i]->resp_retcode = 0;
char *respBuf = malloc (1);
respBuf[0] = '\0';
resp[i]->resp = respBuf;
break;
}
case PAM_PROMPT_ECHO_ON:
case PAM_ERROR_MSG:
default:
return PAM_CONV_ERR;
}
}
return PAM_SUCCESS;
}
/* service: PAM service name (for example, "login")
* username, password: just what they say
* returns 0 with successul authentication, non-zero otherwise.
*/
int
do_pam_login (char *service, char *username, char *password)
{
int k;
struct pam_conv pamc;
pam_handle_t *pamh;
pamc.conv = conv;
pamc.appdata_ptr = (void *) password;
k = pam_start (service, username, &pamc, &pamh);
if (k != PAM_SUCCESS)
goto end;
k = pam_authenticate (pamh, 0);
if (k != PAM_SUCCESS)
goto end;
end:
pam_end (pamh, k | PAM_SILENT);
/* just in case PAM_SUCCESS someday becomes nonzero */
if (k == PAM_SUCCESS)
k = 0;
return k;
}
/* A simple token generator using the basic sdbm hash function. We use it to
* generate login token ids. This token generator returns 0 if something went
* wrong.
*
* based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
* and public domain example by [email protected]
* status: public domain. keep it that way.
*/
unsigned long
authtoken()
{
int j;
char *p;
char buf[TOK_BUF];
unsigned long ans = 0;
/* disallow too short tokens */
while(ans < 10000)
{
FILE *f = fopen( "/dev/urandom", "r");
if(!f) return 0;
fread(buf, 1, TOK_BUF, f);
fclose(f);
p = buf;
while((j=*p++))
ans = j + (ans << 6) + (ans << 16) - ans;
}
return ans;
}
/* addtoken
* Add a new authtoken to the list. If there is a conflict, return NULL and
* don't add the new token. Otherwise return the new head (and modify head)
* that points to the new head of the list. Aquire the big lock before calling
* this.
*/
token_list *
addtoken(token_list *head, unsigned long val, uid_t uid)
{
token_list *new;
token_list *t = head;
/* Scan the list for collision. Also eject timed out tokens from the list. */
while(t)
{
if(t->val == val) return NULL;
// XXX check time out (todo)
t = (token_list *)t->next;
}
new = (token_list *)malloc(sizeof(token_list));
new->val = val;
new->uid = uid;
new->time = time(NULL);
new->next = (void *)head;
head = new;
return head;
}
/* removetoken
* remove a token from the list, deallocating the token entry.
* Return the head of the list (which may change).
*/
token_list *
removetoken(token_list *item, unsigned long val)
{
if (item == NULL)
return NULL;
if (item->val == val)
{
token_list * nextitem;
nextitem = item->next;
free(item);
return nextitem;
}
item->next = removetoken(item->next, val);
return item;
}
/* Look up a uid from a user name string. Return an
* invalid uid_t if not found.
*/
uid_t
username2uid(char *username)
{
struct passwd pwd;
struct passwd *result;
char *buf;
size_t bufsize;
bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1) /* Value was indeterminate */
bufsize = 16384; /* Should be more than enough */
buf = malloc (bufsize);
if (buf == NULL)
{
return -1;
}
getpwnam_r (username, &pwd, buf, bufsize, &result);
if (result == NULL)
{
free(buf);
return -1;
}
free(buf);
return pwd.pw_uid;
}