From 67ce05ee0351a4d014a726e7a2e6757e13e2a201 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 14 May 2009 12:42:05 +0200 Subject: added new pam client protocol --- server/responder/pam/pamsrv_cmd.c | 133 +++++++++++++++++++++++++++++++++++- sss_client/pam_sss.c | 138 +++++++++++++++++++++++++++++++++++++- sss_client/sss_cli.h | 15 ++++- 3 files changed, 282 insertions(+), 4 deletions(-) diff --git a/server/responder/pam/pamsrv_cmd.c b/server/responder/pam/pamsrv_cmd.c index 02b52138e..00765d47c 100644 --- a/server/responder/pam/pamsrv_cmd.c +++ b/server/responder/pam/pamsrv_cmd.c @@ -29,6 +29,124 @@ #include "responder/pam/pamsrv.h" #include "db/sysdb.h" +static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, uint8_t *body, size_t blen, size_t *c) { + size_t data_size; + + if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL; + + data_size = ((uint32_t *)&body[*c])[0]; + *c += sizeof(uint32_t); + if (data_size < sizeof(uint32_t) || (*c)+(data_size) > blen) return EINVAL; + *size = data_size - sizeof(uint32_t); + + *type = ((uint32_t *)&body[*c])[0]; + *c += sizeof(uint32_t); + + *tok = body+(*c); + + *c += (*size); + + return EOK; +} + +static int extract_string(char **var, uint8_t *body, size_t blen, size_t *c) { + uint32_t size; + uint8_t *str; + + if (blen-(*c) < sizeof(uint32_t)+1) return EINVAL; + + size = ((uint32_t *)&body[*c])[0]; + *c += sizeof(uint32_t); + if (*c+size > blen) return EINVAL; + + str = body+(*c); + + if (str[size-1]!='\0') return EINVAL; + + *c += size; + + *var = (char *) str; + + return EOK; +} + +static int pam_parse_in_data_v2(struct sss_names_ctx *snctx, + struct pam_data *pd, + uint8_t *body, size_t blen) +{ + size_t c; + uint32_t type; + uint32_t size; + char *pam_user; + int ret; + + if (blen < 4*sizeof(uint32_t)+2 || + ((uint32_t *)body)[0] != START_OF_PAM_REQUEST || + ((uint32_t *)(&body[blen - sizeof(uint32_t)]))[0] != END_OF_PAM_REQUEST) { + DEBUG(1, ("Received data is invalid.\n")); + return EINVAL; + } + + c = sizeof(uint32_t); + do { + type = ((uint32_t *)&body[c])[0]; + c += sizeof(uint32_t); + if (c > blen) return EINVAL; + + switch(type) { + case PAM_ITEM_USER: + ret = extract_string(&pam_user, body, blen, &c); + if (ret != EOK) return ret; + + ret = sss_parse_name(pd, snctx, pam_user, + &pd->domain, &pd->user); + if (ret != EOK) return ret; + break; + case PAM_ITEM_SERVICE: + ret = extract_string(&pd->service, body, blen, &c); + if (ret != EOK) return ret; + break; + case PAM_ITEM_TTY: + ret = extract_string(&pd->tty, body, blen, &c); + if (ret != EOK) return ret; + break; + case PAM_ITEM_RUSER: + ret = extract_string(&pd->ruser, body, blen, &c); + if (ret != EOK) return ret; + break; + case PAM_ITEM_RHOST: + ret = extract_string(&pd->rhost, body, blen, &c); + if (ret != EOK) return ret; + break; + case PAM_ITEM_AUTHTOK: + ret = extract_authtok(&pd->authtok_type, &pd->authtok_size, + &pd->authtok, body, blen, &c); + if (ret != EOK) return ret; + break; + case PAM_ITEM_NEWAUTHTOK: + ret = extract_authtok(&pd->newauthtok_type, + &pd->newauthtok_size, + &pd->newauthtok, body, blen, &c); + if (ret != EOK) return ret; + break; + case END_OF_PAM_REQUEST: + if (c != blen) return EINVAL; + break; + default: + DEBUG(1,("Ignoring unknown data type [%d].\n", type)); + size = ((uint32_t *)&body[c])[0]; + c += size+sizeof(uint32_t); + } + } while(c < blen); + + if (pd->user == NULL || *pd->user == '\0') return EINVAL; + + DEBUG_PAM_DATA(4, pd); + + return EOK; + +} + static int pam_parse_in_data(struct sss_names_ctx *snctx, struct pam_data *pd, uint8_t *body, size_t blen) @@ -307,7 +425,19 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) pd->cmd = pam_cmd; pd->priv = cctx->priv; - ret = pam_parse_in_data(cctx->rctx->names, pd, body, blen); + + switch (cctx->cli_protocol_version->version) { + case 1: + ret = pam_parse_in_data(cctx->rctx->names, pd, body, blen); + break; + case 2: + ret = pam_parse_in_data_v2(cctx->rctx->names, pd, body, blen); + break; + default: + DEBUG(1, ("Illegal protocol version [%d].\n", + cctx->cli_protocol_version->version)); + ret = EINVAL; + } if (ret != EOK) { talloc_free(preq); ret = EINVAL; @@ -660,6 +790,7 @@ struct cli_protocol_version *register_cli_protocol_version(void) { static struct cli_protocol_version pam_cli_protocol_version[] = { {1, "2008-09-05", "initial version, \\0 terminated strings"}, + {2, "2009-05-12", "new format "}, {0, NULL, NULL} }; diff --git a/sss_client/pam_sss.c b/sss_client/pam_sss.c index 3ed642a7a..2b676f078 100644 --- a/sss_client/pam_sss.c +++ b/sss_client/pam_sss.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,8 @@ struct pam_items { size_t pam_authtok_size; int pam_newauthtok_type; size_t pam_newauthtok_size; + char *pam_cli_locale; + size_t pam_cli_locale_size; }; #define DEBUG_MGS_LEN 1024 @@ -71,6 +74,126 @@ static void logger(pam_handle_t *pamh, int level, const char *fmt, ...) { va_end(ap); } + +static size_t add_authtok_item(enum pam_item_type type, + enum sss_authtok_type authtok_type, + const char *tok, const size_t size, + uint8_t *buf) { + size_t rp=0; + + if (tok == NULL) return 0; + + ((uint32_t *)(&buf[rp]))[0] = type; + rp += sizeof(uint32_t); + + ((uint32_t *)(&buf[rp]))[0] = size + sizeof(uint32_t); + rp += sizeof(uint32_t); + + ((uint32_t *)(&buf[rp]))[0] = authtok_type; + rp += sizeof(uint32_t); + + memcpy(&buf[rp], tok, size); + rp += size; + + return rp; +} + +static size_t add_string_item(enum pam_item_type type, const char *str, + const size_t size, uint8_t *buf) { + size_t rp=0; + + if (*str == '\0') return 0; + + ((uint32_t *)(&buf[rp]))[0] = type; + rp += sizeof(uint32_t); + + ((uint32_t *)(&buf[rp]))[0] = size; + rp += sizeof(uint32_t); + + memcpy(&buf[rp], str, size); + rp += size; + + return rp; +} + +static int pack_message_v2(struct pam_items *pi, size_t *size, uint8_t **buffer) { + int len; + uint8_t *buf; + int rp; + + len = sizeof(uint32_t) + + 2*sizeof(uint32_t) + pi->pam_user_size + + sizeof(uint32_t); + len += *pi->pam_service != '\0' ? + 2*sizeof(uint32_t) + pi->pam_service_size : 0; + len += *pi->pam_tty != '\0' ? + 2*sizeof(uint32_t) + pi->pam_tty_size : 0; + len += *pi->pam_ruser != '\0' ? + 2*sizeof(uint32_t) + pi->pam_ruser_size : 0; + len += *pi->pam_rhost != '\0' ? + 2*sizeof(uint32_t) + pi->pam_rhost_size : 0; + len += *pi->pam_cli_locale != '\0' ? + 2*sizeof(uint32_t) + pi->pam_cli_locale_size : 0; + len += pi->pam_authtok != NULL ? + 3*sizeof(uint32_t) + pi->pam_authtok_size : 0; + len += pi->pam_newauthtok != NULL ? + 3*sizeof(uint32_t) + pi->pam_newauthtok_size : 0; + + buf = malloc(len); + if (buf == NULL) { + D(("malloc failed.")); + return PAM_BUF_ERR; + } + + rp = 0; + ((uint32_t *)(&buf[rp]))[0] = START_OF_PAM_REQUEST; + rp += sizeof(uint32_t); + + rp += add_string_item(PAM_ITEM_USER, pi->pam_user, pi->pam_user_size, + &buf[rp]); + + rp += add_string_item(PAM_ITEM_SERVICE, pi->pam_service, + pi->pam_service_size, &buf[rp]); + + rp += add_string_item(PAM_ITEM_TTY, pi->pam_tty, pi->pam_tty_size, + &buf[rp]); + + rp += add_string_item(PAM_ITEM_RUSER, pi->pam_ruser, pi->pam_ruser_size, + &buf[rp]); + + rp += add_string_item(PAM_ITEM_RHOST, pi->pam_rhost, pi->pam_rhost_size, + &buf[rp]); + + rp += add_string_item(PAM_CLI_LOCALE, pi->pam_cli_locale, + pi->pam_cli_locale_size, &buf[rp]); + + rp += add_authtok_item(PAM_ITEM_AUTHTOK, pi->pam_authtok_type, + pi->pam_authtok, pi->pam_authtok_size, &buf[rp]); + _pam_overwrite_n((void *)pi->pam_authtok, pi->pam_authtok_size); + free((void *)pi->pam_authtok); + pi->pam_authtok = NULL; + + rp += add_authtok_item(PAM_ITEM_NEWAUTHTOK, pi->pam_newauthtok_type, + pi->pam_newauthtok, pi->pam_newauthtok_size, + &buf[rp]); + _pam_overwrite_n((void *)pi->pam_newauthtok, pi->pam_newauthtok_size); + free((void *)pi->pam_newauthtok); + pi->pam_newauthtok = NULL; + + ((uint32_t *)(&buf[rp]))[0] = END_OF_PAM_REQUEST; + rp += sizeof(uint32_t); + + if (rp != len) { + D(("error during packet creation.")); + return PAM_BUF_ERR; + } + + *size = len; + *buffer = buf; + + return 0; +} + static int pack_message(struct pam_items *pi, size_t *size, uint8_t **buffer) { int len; uint8_t *buf; @@ -347,6 +470,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf) static int get_pam_items(pam_handle_t *pamh, struct pam_items *pi) { int ret; + char *cli_locale; pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY; pi->pam_authtok = NULL; @@ -388,6 +512,15 @@ static int get_pam_items(pam_handle_t *pamh, struct pam_items *pi) if (ret != PAM_SUCCESS) return ret; if (pi->pamstack_oldauthtok == NULL) pi->pamstack_oldauthtok=""; + cli_locale = setlocale(LC_ALL, NULL); + if (cli_locale == NULL) { + pi->pam_cli_locale = ""; + } else { + pi->pam_cli_locale = strdup(cli_locale); + if (pi->pam_cli_locale == NULL) return PAM_BUF_ERR; + } + pi->pam_cli_locale_size = strlen(pi->pam_cli_locale)+1; + return PAM_SUCCESS; } @@ -406,6 +539,7 @@ static void print_pam_items(struct pam_items pi) if (pi.pam_newauthtok != NULL) { D(("Newauthtok: %s", *pi.pam_newauthtok!='\0' ? pi.pam_newauthtok : "(not available)")); } + D(("Locale: %s", *pi.pam_cli_locale!='\0' ? pi.pam_cli_locale : "(not available)")); } static int pam_sss(int task, pam_handle_t *pamh, int pam_flags, int argc, @@ -550,7 +684,7 @@ static int pam_sss(int task, pam_handle_t *pamh, int pam_flags, int argc, goto done; } pi.pam_newauthtok_type = SSS_AUTHTOK_TYPE_PASSWORD; - pi.pam_newauthtok_size=strlen(pi.pam_authtok); + pi.pam_newauthtok_size=strlen(pi.pam_newauthtok); } if (flags & FLAGS_FORWARD_PASS) { @@ -564,7 +698,7 @@ static int pam_sss(int task, pam_handle_t *pamh, int pam_flags, int argc, print_pam_items(pi); - ret = pack_message(&pi, &rd.len, &buf); + ret = pack_message_v2(&pi, &rd.len, &buf); if (ret != 0) { D(("pack_message failed.")); pam_status = PAM_SYSTEM_ERR; diff --git a/sss_client/sss_cli.h b/sss_client/sss_cli.h index ba412fd07..63daf7bca 100644 --- a/sss_client/sss_cli.h +++ b/sss_client/sss_cli.h @@ -22,7 +22,7 @@ #define SSS_PAM_PRIV_SOCKET_NAME "/var/lib/sss/pipes/private/pam" #define SSS_NSS_PROTOCOL_VERSION 1 -#define SSS_PAM_PROTOCOL_VERSION 1 +#define SSS_PAM_PROTOCOL_VERSION 2 enum sss_cli_command { /* null */ @@ -138,8 +138,21 @@ enum sss_authtok_type { SSS_AUTHTOK_TYPE_PASSWORD = 0x0001, }; +#define START_OF_PAM_REQUEST 0x4d415049 #define END_OF_PAM_REQUEST 0x4950414d +enum pam_item_type { + PAM_ITEM_EMPTY = 0x0000, + PAM_ITEM_USER, + PAM_ITEM_SERVICE, + PAM_ITEM_TTY, + PAM_ITEM_RUSER, + PAM_ITEM_RHOST, + PAM_ITEM_AUTHTOK, + PAM_ITEM_NEWAUTHTOK, + PAM_CLI_LOCALE, +}; + #define SSS_NSS_MAX_ENTRIES 256 #define SSS_NSS_HEADER_SIZE (sizeof(uint32_t) * 4) struct sss_cli_req_data { -- cgit