test.libpamc.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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. #include <stdio.h>
  7. #include <stdint.h>
  8. #include <string.h>
  9. #include <security/pam_client.h>
  10. #include <ctype.h>
  11. struct internal_packet {
  12. int length;
  13. int at;
  14. char *buffer;
  15. };
  16. void append_data(struct internal_packet *packet, int extra, const char *data)
  17. {
  18. if ((extra + packet->at) >= packet->length) {
  19. if (packet->length == 0) {
  20. packet->length = 1000;
  21. }
  22. /* make sure we have at least a char extra space available */
  23. while (packet->length <= (extra + packet->at)) {
  24. packet->length <<= 1;
  25. }
  26. packet->buffer = realloc(packet->buffer, packet->length);
  27. if (packet->buffer == NULL) {
  28. fprintf(stderr, "out of memory\n");
  29. exit(1);
  30. }
  31. }
  32. if (data != NULL) {
  33. memcpy(packet->at + packet->buffer, data, extra);
  34. }
  35. packet->at += extra;
  36. /* assisting string manipulation */
  37. packet->buffer[packet->at] = '\0';
  38. }
  39. void append_string(struct internal_packet *packet, const char *string,
  40. int with_nul)
  41. {
  42. append_data(packet, strlen(string) + (with_nul ? 1:0), string);
  43. }
  44. char *identify_secret(char *identity)
  45. {
  46. struct internal_packet temp_packet;
  47. FILE *secrets;
  48. int length_id;
  49. temp_packet.length = temp_packet.at = 0;
  50. temp_packet.buffer = NULL;
  51. append_string(&temp_packet, "/home/", 0);
  52. append_string(&temp_packet, getlogin(), 0);
  53. append_string(&temp_packet, "/.secret@here", 1);
  54. secrets = fopen(temp_packet.buffer, "r");
  55. if (secrets == NULL) {
  56. fprintf(stderr, "server: failed to open\n [%s]\n",
  57. temp_packet.buffer);
  58. exit(1);
  59. }
  60. length_id = strlen(identity);
  61. for (;;) {
  62. char *secret = NULL;
  63. temp_packet.at = 0;
  64. if (fgets(temp_packet.buffer, temp_packet.length, secrets) == NULL) {
  65. fclose(secrets);
  66. return NULL;
  67. }
  68. if (memcmp(temp_packet.buffer, identity, length_id)) {
  69. continue;
  70. }
  71. fclose(secrets);
  72. for (secret=temp_packet.buffer; *secret; ++secret) {
  73. if (*secret == ' ' || *secret == '\n' || *secret == '\t') {
  74. break;
  75. }
  76. }
  77. for (; *secret; ++secret) {
  78. if (!(*secret == ' ' || *secret == '\n' || *secret == '\t')) {
  79. break;
  80. }
  81. }
  82. for (temp_packet.buffer=secret; *temp_packet.buffer;
  83. ++temp_packet.buffer) {
  84. if (*temp_packet.buffer == ' ' || *temp_packet.buffer == '\n'
  85. || *temp_packet.buffer == '\t') {
  86. break;
  87. }
  88. }
  89. if (*temp_packet.buffer) {
  90. *temp_packet.buffer = '\0';
  91. }
  92. return secret;
  93. }
  94. /* NOT REACHED */
  95. }
  96. /*
  97. * This is a hack, and is fundamentally insecure. All our secrets will be
  98. * displayed on the command line for someone doing 'ps' to see. This
  99. * is just for programming convenience in this instance, since this
  100. * program is simply a regression test. The pam_secret module should
  101. * not do this, but make use of md5 routines directly.
  102. */
  103. char *create_digest(int length, const char *raw)
  104. {
  105. struct internal_packet temp_packet;
  106. FILE *pipe;
  107. temp_packet.length = temp_packet.at = 0;
  108. temp_packet.buffer = NULL;
  109. append_string(&temp_packet, "echo -n '", 0);
  110. append_string(&temp_packet, raw, 0);
  111. append_string(&temp_packet, "'|/usr/bin/md5sum -", 1);
  112. fprintf(stderr, "am attempting to run [%s]\n", temp_packet.buffer);
  113. pipe = popen(temp_packet.buffer, "r");
  114. if (pipe == NULL) {
  115. fprintf(stderr, "server: failed to run\n [%s]\n", temp_packet.buffer);
  116. exit(1);
  117. }
  118. temp_packet.at = 0;
  119. append_data(&temp_packet, 32, NULL);
  120. if (fgets(temp_packet.buffer, 33, pipe) == NULL) {
  121. fprintf(stderr, "server: failed to read digest\n");
  122. exit(1);
  123. }
  124. if (strlen(temp_packet.buffer) != 32) {
  125. fprintf(stderr, "server: digest was not 32 chars?? [%s]\n",
  126. temp_packet.buffer);
  127. exit(1);
  128. }
  129. fclose(pipe);
  130. return temp_packet.buffer;
  131. }
  132. void packet_to_prompt(pamc_bp_t *prompt_p, uint8_t control,
  133. struct internal_packet *packet)
  134. {
  135. PAM_BP_RENEW(prompt_p, control, packet->at);
  136. PAM_BP_FILL(*prompt_p, 0, packet->at, packet->buffer);
  137. packet->at = 0;
  138. }
  139. void prompt_to_packet(pamc_bp_t prompt, struct internal_packet *packet)
  140. {
  141. int data_length;
  142. data_length = PAM_BP_LENGTH(prompt);
  143. packet->at = 0;
  144. append_data(packet, data_length, NULL);
  145. PAM_BP_EXTRACT(prompt, 0, data_length, packet->buffer);
  146. fprintf(stderr, "server received[%d]: {%d|0x%.2x|%s}\n",
  147. data_length,
  148. PAM_BP_SIZE(prompt), PAM_BP_RCONTROL(prompt),
  149. PAM_BP_RDATA(prompt));
  150. }
  151. int main(int argc, char **argv)
  152. {
  153. pamc_handle_t pch;
  154. pamc_bp_t prompt = NULL;
  155. struct internal_packet packet_data, *packet;
  156. char *temp_string, *secret, *user, *a_cookie, *seqid, *digest;
  157. const char *cookie = "123451234512345";
  158. int retval;
  159. packet = &packet_data;
  160. packet->length = 0;
  161. packet->at = 0;
  162. packet->buffer = NULL;
  163. pch = pamc_start();
  164. if (pch == NULL) {
  165. fprintf(stderr, "server: unable to get a handle from libpamc\n");
  166. exit(1);
  167. }
  168. temp_string = getlogin();
  169. if (temp_string == NULL) {
  170. fprintf(stderr, "server: who are you?\n");
  171. exit(1);
  172. }
  173. #define DOMAIN "@local.host"
  174. user = malloc(1+strlen(temp_string)+strlen(DOMAIN));
  175. if (user == NULL) {
  176. fprintf(stderr, "server: out of memory for user id\n");
  177. exit(1);
  178. }
  179. sprintf(user, "%s%s", temp_string, DOMAIN);
  180. append_string(packet, "secret@here/", 0);
  181. append_string(packet, user, 0);
  182. append_string(packet, "|", 0);
  183. append_string(packet, cookie, 0);
  184. packet_to_prompt(&prompt, PAM_BPC_SELECT, packet);
  185. /* get the library to accept the first packet (which should load
  186. the secret@here agent) */
  187. retval = pamc_converse(pch, &prompt);
  188. fprintf(stderr, "server: after conversation\n");
  189. if (PAM_BP_RCONTROL(prompt) != PAM_BPC_OK) {
  190. fprintf(stderr, "server: prompt had unexpected control type: %u\n",
  191. PAM_BP_RCONTROL(prompt));
  192. exit(1);
  193. }
  194. fprintf(stderr, "server: got a prompt back\n");
  195. prompt_to_packet(prompt, packet);
  196. temp_string = strtok(packet->buffer, "|");
  197. if (temp_string == NULL) {
  198. fprintf(stderr, "server: prompt does not contain anything");
  199. exit(1);
  200. }
  201. seqid = strdup(temp_string);
  202. if (seqid == NULL) {
  203. fprintf(stderr, "server: unable to store sequence id\n");
  204. }
  205. temp_string = strtok(NULL, "|");
  206. if (temp_string == NULL) {
  207. fprintf(stderr, "server: no cookie from agent\n");
  208. exit(1);
  209. }
  210. a_cookie = strdup(temp_string);
  211. if (a_cookie == NULL) {
  212. fprintf(stderr, "server: no memory to store agent cookie\n");
  213. exit(1);
  214. }
  215. fprintf(stderr, "server: agent responded with {%s|%s}\n", seqid, a_cookie);
  216. secret = identify_secret(user);
  217. fprintf(stderr, "server: secret=%s\n", secret);
  218. /* now, we construct the response */
  219. packet->at = 0;
  220. append_string(packet, a_cookie, 0);
  221. append_string(packet, "|", 0);
  222. append_string(packet, cookie, 0);
  223. append_string(packet, "|", 0);
  224. append_string(packet, secret, 0);
  225. fprintf(stderr, "server: get digest of %s\n", packet->buffer);
  226. digest = create_digest(packet->at, packet->buffer);
  227. fprintf(stderr, "server: secret=%s, digest=%s\n", secret, digest);
  228. packet->at = 0;
  229. append_string(packet, seqid, 0);
  230. append_string(packet, "|", 0);
  231. append_string(packet, digest, 0);
  232. packet_to_prompt(&prompt, PAM_BPC_OK, packet);
  233. retval = pamc_converse(pch, &prompt);
  234. fprintf(stderr, "server: after 2nd conversation\n");
  235. if (PAM_BP_RCONTROL(prompt) != PAM_BPC_DONE) {
  236. fprintf(stderr, "server: 2nd prompt had unexpected control type: %u\n",
  237. PAM_BP_RCONTROL(prompt));
  238. exit(1);
  239. }
  240. prompt_to_packet(prompt, packet);
  241. PAM_BP_RENEW(&prompt, 0, 0);
  242. temp_string = strtok(packet->buffer, "|");
  243. if (temp_string == NULL) {
  244. fprintf(stderr, "no digest from agent\n");
  245. exit(1);
  246. }
  247. temp_string = strdup(temp_string);
  248. packet->at = 0;
  249. append_string(packet, secret, 0);
  250. append_string(packet, "|", 0);
  251. append_string(packet, cookie, 0);
  252. append_string(packet, "|", 0);
  253. append_string(packet, a_cookie, 0);
  254. fprintf(stderr, "server: get digest of %s\n", packet->buffer);
  255. digest = create_digest(packet->at, packet->buffer);
  256. fprintf(stderr, "server: digest=%s\n", digest);
  257. if (strcmp(digest, temp_string)) {
  258. fprintf(stderr, "server: agent doesn't know the secret\n");
  259. fprintf(stderr, "server: agent says: [%s]\n"
  260. "server: server says: [%s]\n", temp_string, digest);
  261. exit(1);
  262. } else {
  263. fprintf(stderr, "server: agent seems to know the secret\n");
  264. packet->at = 0;
  265. append_string(packet, cookie, 0);
  266. append_string(packet, "|", 0);
  267. append_string(packet, secret, 0);
  268. append_string(packet, "|", 0);
  269. append_string(packet, a_cookie, 0);
  270. digest = create_digest(packet->at, packet->buffer);
  271. fprintf(stderr, "server: putenv(\"AUTH_SESSION_TICKET=%s\")\n",
  272. digest);
  273. }
  274. retval = pamc_end(&pch);
  275. fprintf(stderr, "server: agent(s) were %shappy to terminate\n",
  276. retval == PAM_BPC_TRUE ? "":"un");
  277. exit(!retval);
  278. }