Remove extra whitespace at the end of some lines.
[dragonfly.git] / contrib / libpam / libpamc / test / regress / test.libpamc.c
1 /*
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.
5  */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <security/pam_client.h>
10 #include <ctype.h>
11
12 struct internal_packet {
13     int length;
14     int at;
15     char *buffer;
16 };
17
18
19 void append_data(struct internal_packet *packet, int extra, const char *data)
20 {
21     if ((extra + packet->at) >= packet->length) {
22         if (packet->length == 0) {
23             packet->length = 1000;
24         }
25         /* make sure we have at least a char extra space available */
26         while (packet->length <= (extra + packet->at)) {
27             packet->length <<= 1;
28         }
29         packet->buffer = realloc(packet->buffer, packet->length);
30         if (packet->buffer == NULL) {
31             fprintf(stderr, "out of memory\n");
32             exit(1);
33         }
34     }
35
36     if (data != NULL) {
37         memcpy(packet->at + packet->buffer, data, extra);
38     }
39     packet->at += extra;
40
41     /* assisting string manipulation */
42     packet->buffer[packet->at] = '\0';
43 }
44
45 void append_string(struct internal_packet *packet, const char *string,
46                    int with_nul)
47 {
48     append_data(packet, strlen(string) + (with_nul ? 1:0), string);
49 }
50
51 char *identify_secret(char *identity)
52 {
53     struct internal_packet temp_packet;
54     FILE *secrets;
55     int length_id;
56
57     temp_packet.length = temp_packet.at = 0;
58     temp_packet.buffer = NULL;
59
60     append_string(&temp_packet, "/home/", 0);
61     append_string(&temp_packet, getlogin(), 0);
62     append_string(&temp_packet, "/.secret@here", 1);
63
64     secrets = fopen(temp_packet.buffer, "r");
65     if (secrets == NULL) {
66         fprintf(stderr, "server: failed to open\n  [%s]\n",
67                 temp_packet.buffer);
68         exit(1);
69     }
70
71     length_id = strlen(identity);
72     for (;;) {
73         char *secret = NULL;
74         temp_packet.at = 0;
75
76         if (fgets(temp_packet.buffer, temp_packet.length, secrets) == NULL) {
77             fclose(secrets);
78             return NULL;
79         }
80
81         if (memcmp(temp_packet.buffer, identity, length_id)) {
82             continue;
83         }
84
85         fclose(secrets);
86         for (secret=temp_packet.buffer; *secret; ++secret) {
87             if (*secret == ' ' || *secret == '\n' || *secret == '\t') {
88                 break;
89             }
90         }
91         for (; *secret; ++secret) {
92             if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) {
93                 break;
94             }
95         }
96
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') {
101                 break;
102             }
103         }
104         if (*temp_packet.buffer) {
105             *temp_packet.buffer = '\0';
106         }
107
108         return secret;
109     }
110
111     /* NOT REACHED */
112 }
113
114 /*
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.
120  */
121
122 char *create_digest(int length, const char *raw)
123 {
124     struct internal_packet temp_packet;
125     FILE *pipe;
126
127     temp_packet.length = temp_packet.at = 0;
128     temp_packet.buffer = NULL;
129
130     append_string(&temp_packet, "echo -n '", 0);
131     append_string(&temp_packet, raw, 0);
132     append_string(&temp_packet, "'|/usr/bin/md5sum -", 1);
133
134     fprintf(stderr, "am attempting to run [%s]\n", temp_packet.buffer);
135
136     pipe = popen(temp_packet.buffer, "r");
137     if (pipe == NULL) {
138         fprintf(stderr, "server: failed to run\n  [%s]\n", temp_packet.buffer);
139         exit(1);
140     }
141
142     temp_packet.at = 0;
143     append_data(&temp_packet, 32, NULL);
144
145     if (fgets(temp_packet.buffer, 33, pipe) == NULL) {
146         fprintf(stderr, "server: failed to read digest\n");
147         exit(1);
148     }
149     if (strlen(temp_packet.buffer) != 32) {
150         fprintf(stderr, "server: digest was not 32 chars?? [%s]\n",
151                 temp_packet.buffer);
152         exit(1);
153     }
154
155     fclose(pipe);
156
157     return temp_packet.buffer;
158 }
159
160 void packet_to_prompt(pamc_bp_t *prompt_p, __u8 control,
161                       struct internal_packet *packet)
162 {
163     PAM_BP_RENEW(prompt_p, control, packet->at);
164     PAM_BP_FILL(*prompt_p, 0, packet->at, packet->buffer);
165     packet->at = 0;
166 }
167
168 void prompt_to_packet(pamc_bp_t prompt, struct internal_packet *packet)
169 {
170     int data_length;
171
172     data_length = PAM_BP_LENGTH(prompt);
173     packet->at = 0;
174     append_data(packet, data_length, NULL);
175     
176     PAM_BP_EXTRACT(prompt, 0, data_length, packet->buffer);
177
178     fprintf(stderr, "server received[%d]: {%d|0x%.2x|%s}\n",
179             data_length,
180             PAM_BP_SIZE(prompt), PAM_BP_RCONTROL(prompt),
181             PAM_BP_RDATA(prompt));
182 }
183
184 int main(int argc, char **argv)
185 {
186     pamc_handle_t pch;
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";
191     int retval;
192
193     packet = &packet_data;
194     packet->length = 0;
195     packet->at = 0;
196     packet->buffer = NULL;
197
198     pch = pamc_start();
199     if (pch == NULL) {
200         fprintf(stderr, "server: unable to get a handle from libpamc\n");
201         exit(1);
202     }
203
204     temp_string = getlogin();
205     if (temp_string == NULL) {
206         fprintf(stderr, "server: who are you?\n");
207         exit(1);
208     }
209 #define DOMAIN "@local.host"
210     user = malloc(1+strlen(temp_string)+strlen(DOMAIN));
211     if (user == NULL) {
212         fprintf(stderr, "server: out of memory for user id\n");
213         exit(1);
214     }
215     sprintf(user, "%s%s", temp_string, DOMAIN);
216
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);
222
223     /* get the library to accept the first packet (which should load
224        the secret@here agent) */
225
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));
231         exit(1);
232     }
233
234     fprintf(stderr, "server: got a prompt back\n");
235
236     prompt_to_packet(prompt, packet);
237
238     temp_string = strtok(packet->buffer, "|");
239     if (temp_string == NULL) {
240         fprintf(stderr, "server: prompt does not contain anything");
241         exit(1);
242     }
243     seqid = strdup(temp_string);
244     if (seqid == NULL) {
245         fprintf(stderr, "server: unable to store sequence id\n");
246     }
247
248     temp_string = strtok(NULL, "|");
249     if (temp_string == NULL) {
250         fprintf(stderr, "server: no cookie from agent\n");
251         exit(1);
252     }
253     a_cookie = strdup(temp_string);
254     if (a_cookie == NULL) {
255         fprintf(stderr, "server: no memory to store agent cookie\n");
256         exit(1);
257     }
258
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);
262
263     /* now, we construct the response */
264     packet->at = 0;
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);
270
271     fprintf(stderr, "server: get digest of %s\n", packet->buffer);
272
273     digest = create_digest(packet->at, packet->buffer);
274
275     fprintf(stderr, "server: secret=%s, digest=%s\n", secret, digest);
276
277     packet->at = 0;
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);
282
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));
288         exit(1);
289     }
290
291     prompt_to_packet(prompt, packet);
292     PAM_BP_RENEW(&prompt, 0, 0);
293
294     temp_string = strtok(packet->buffer, "|");
295     if (temp_string == NULL) {
296         fprintf(stderr, "no digest from agent\n");
297         exit(1);
298     }
299     temp_string = strdup(temp_string);
300
301     packet->at = 0;
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);
307
308     fprintf(stderr, "server: get digest of %s\n", packet->buffer);
309
310     digest = create_digest(packet->at, packet->buffer);
311
312     fprintf(stderr, "server: digest=%s\n", digest);
313
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);
318         exit(1);
319     } else {
320         fprintf(stderr, "server: agent seems to know the secret\n");
321
322         packet->at = 0;
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);
328
329         digest = create_digest(packet->at, packet->buffer);
330
331         fprintf(stderr, "server: putenv(\"AUTH_SESSION_TICKET=%s\")\n",
332                 digest);
333     }
334
335     
336     retval = pamc_end(&pch);
337
338     fprintf(stderr, "server: agent(s) were %shappy to terminate\n",
339             retval == PAM_BPC_TRUE ? "":"un");
340
341     exit(!retval);
342 }