2 * This is a small test program for testing libpamc against the
3 * secret@here agent. It does the same as the test.secret@here perl
4 * script in this directory, but via the libpamc API.
9 #include <security/pam_client.h>
12 struct internal_packet {
19 void append_data(struct internal_packet *packet, int extra, const char *data)
21 if ((extra + packet->at) >= packet->length) {
22 if (packet->length == 0) {
23 packet->length = 1000;
25 /* make sure we have at least a char extra space available */
26 while (packet->length <= (extra + packet->at)) {
29 packet->buffer = realloc(packet->buffer, packet->length);
30 if (packet->buffer == NULL) {
31 fprintf(stderr, "out of memory\n");
37 memcpy(packet->at + packet->buffer, data, extra);
41 /* assisting string manipulation */
42 packet->buffer[packet->at] = '\0';
45 void append_string(struct internal_packet *packet, const char *string,
48 append_data(packet, strlen(string) + (with_nul ? 1:0), string);
51 char *identify_secret(char *identity)
53 struct internal_packet temp_packet;
57 temp_packet.length = temp_packet.at = 0;
58 temp_packet.buffer = NULL;
60 append_string(&temp_packet, "/home/", 0);
61 append_string(&temp_packet, getlogin(), 0);
62 append_string(&temp_packet, "/.secret@here", 1);
64 secrets = fopen(temp_packet.buffer, "r");
65 if (secrets == NULL) {
66 fprintf(stderr, "server: failed to open\n [%s]\n",
71 length_id = strlen(identity);
76 if (fgets(temp_packet.buffer, temp_packet.length, secrets) == NULL) {
81 if (memcmp(temp_packet.buffer, identity, length_id)) {
86 for (secret=temp_packet.buffer; *secret; ++secret) {
87 if (*secret == ' ' || *secret == '\n' || *secret == '\t') {
91 for (; *secret; ++secret) {
92 if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) {
97 for (temp_packet.buffer=secret; *temp_packet.buffer;
98 ++temp_packet.buffer) {
99 if (*temp_packet.buffer == ' ' || *temp_packet.buffer == '\n'
100 || *temp_packet.buffer == '\t') {
104 if (*temp_packet.buffer) {
105 *temp_packet.buffer = '\0';
115 * This is a hack, and is fundamentally insecure. All our secrets will be
116 * displayed on the command line for someone doing 'ps' to see. This
117 * is just for programming convenience in this instance, since this
118 * program is simply a regression test. The pam_secret module should
119 * not do this, but make use of md5 routines directly.
122 char *create_digest(int length, const char *raw)
124 struct internal_packet temp_packet;
127 temp_packet.length = temp_packet.at = 0;
128 temp_packet.buffer = NULL;
130 append_string(&temp_packet, "echo -n '", 0);
131 append_string(&temp_packet, raw, 0);
132 append_string(&temp_packet, "'|/usr/bin/md5sum -", 1);
134 fprintf(stderr, "am attempting to run [%s]\n", temp_packet.buffer);
136 pipe = popen(temp_packet.buffer, "r");
138 fprintf(stderr, "server: failed to run\n [%s]\n", temp_packet.buffer);
143 append_data(&temp_packet, 32, NULL);
145 if (fgets(temp_packet.buffer, 33, pipe) == NULL) {
146 fprintf(stderr, "server: failed to read digest\n");
149 if (strlen(temp_packet.buffer) != 32) {
150 fprintf(stderr, "server: digest was not 32 chars?? [%s]\n",
157 return temp_packet.buffer;
160 void packet_to_prompt(pamc_bp_t *prompt_p, __u8 control,
161 struct internal_packet *packet)
163 PAM_BP_RENEW(prompt_p, control, packet->at);
164 PAM_BP_FILL(*prompt_p, 0, packet->at, packet->buffer);
168 void prompt_to_packet(pamc_bp_t prompt, struct internal_packet *packet)
172 data_length = PAM_BP_LENGTH(prompt);
174 append_data(packet, data_length, NULL);
176 PAM_BP_EXTRACT(prompt, 0, data_length, packet->buffer);
178 fprintf(stderr, "server received[%d]: {%d|0x%.2x|%s}\n",
180 PAM_BP_SIZE(prompt), PAM_BP_RCONTROL(prompt),
181 PAM_BP_RDATA(prompt));
184 int main(int argc, char **argv)
187 pamc_bp_t prompt = NULL;
188 struct internal_packet packet_data, *packet;
189 char *temp_string, *secret, *user, *a_cookie, *seqid, *digest;
190 const char *cookie = "123451234512345";
193 packet = &packet_data;
196 packet->buffer = NULL;
200 fprintf(stderr, "server: unable to get a handle from libpamc\n");
204 temp_string = getlogin();
205 if (temp_string == NULL) {
206 fprintf(stderr, "server: who are you?\n");
209 #define DOMAIN "@local.host"
210 user = malloc(1+strlen(temp_string)+strlen(DOMAIN));
212 fprintf(stderr, "server: out of memory for user id\n");
215 sprintf(user, "%s%s", temp_string, DOMAIN);
217 append_string(packet, "secret@here/", 0);
218 append_string(packet, user, 0);
219 append_string(packet, "|", 0);
220 append_string(packet, cookie, 0);
221 packet_to_prompt(&prompt, PAM_BPC_SELECT, packet);
223 /* get the library to accept the first packet (which should load
224 the secret@here agent) */
226 retval = pamc_converse(pch, &prompt);
227 fprintf(stderr, "server: after conversation\n");
228 if (PAM_BP_RCONTROL(prompt) != PAM_BPC_OK) {
229 fprintf(stderr, "server: prompt had unexpected control type: %u\n",
230 PAM_BP_RCONTROL(prompt));
234 fprintf(stderr, "server: got a prompt back\n");
236 prompt_to_packet(prompt, packet);
238 temp_string = strtok(packet->buffer, "|");
239 if (temp_string == NULL) {
240 fprintf(stderr, "server: prompt does not contain anything");
243 seqid = strdup(temp_string);
245 fprintf(stderr, "server: unable to store sequence id\n");
248 temp_string = strtok(NULL, "|");
249 if (temp_string == NULL) {
250 fprintf(stderr, "server: no cookie from agent\n");
253 a_cookie = strdup(temp_string);
254 if (a_cookie == NULL) {
255 fprintf(stderr, "server: no memory to store agent cookie\n");
259 fprintf(stderr, "server: agent responded with {%s|%s}\n", seqid, a_cookie);
260 secret = identify_secret(user);
261 fprintf(stderr, "server: secret=%s\n", secret);
263 /* now, we construct the response */
265 append_string(packet, a_cookie, 0);
266 append_string(packet, "|", 0);
267 append_string(packet, cookie, 0);
268 append_string(packet, "|", 0);
269 append_string(packet, secret, 0);
271 fprintf(stderr, "server: get digest of %s\n", packet->buffer);
273 digest = create_digest(packet->at, packet->buffer);
275 fprintf(stderr, "server: secret=%s, digest=%s\n", secret, digest);
278 append_string(packet, seqid, 0);
279 append_string(packet, "|", 0);
280 append_string(packet, digest, 0);
281 packet_to_prompt(&prompt, PAM_BPC_OK, packet);
283 retval = pamc_converse(pch, &prompt);
284 fprintf(stderr, "server: after 2nd conversation\n");
285 if (PAM_BP_RCONTROL(prompt) != PAM_BPC_DONE) {
286 fprintf(stderr, "server: 2nd prompt had unexpected control type: %u\n",
287 PAM_BP_RCONTROL(prompt));
291 prompt_to_packet(prompt, packet);
292 PAM_BP_RENEW(&prompt, 0, 0);
294 temp_string = strtok(packet->buffer, "|");
295 if (temp_string == NULL) {
296 fprintf(stderr, "no digest from agent\n");
299 temp_string = strdup(temp_string);
302 append_string(packet, secret, 0);
303 append_string(packet, "|", 0);
304 append_string(packet, cookie, 0);
305 append_string(packet, "|", 0);
306 append_string(packet, a_cookie, 0);
308 fprintf(stderr, "server: get digest of %s\n", packet->buffer);
310 digest = create_digest(packet->at, packet->buffer);
312 fprintf(stderr, "server: digest=%s\n", digest);
314 if (strcmp(digest, temp_string)) {
315 fprintf(stderr, "server: agent doesn't know the secret\n");
316 fprintf(stderr, "server: agent says: [%s]\n"
317 "server: server says: [%s]\n", temp_string, digest);
320 fprintf(stderr, "server: agent seems to know the secret\n");
323 append_string(packet, cookie, 0);
324 append_string(packet, "|", 0);
325 append_string(packet, secret, 0);
326 append_string(packet, "|", 0);
327 append_string(packet, a_cookie, 0);
329 digest = create_digest(packet->at, packet->buffer);
331 fprintf(stderr, "server: putenv(\"AUTH_SESSION_TICKET=%s\")\n",
336 retval = pamc_end(&pch);
338 fprintf(stderr, "server: agent(s) were %shappy to terminate\n",
339 retval == PAM_BPC_TRUE ? "":"un");