From b0f167cdf2942ddaeaa03032542e74345ce81308 Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Wed, 22 Aug 2001 02:48:16 +0000 Subject: Added another authentication interface to winbindd. The Challenge Response Authentication Protocol (CRAP) takes a tuple of (username, random challenge, encrypted lm password, encrypted nt password) where the passwords are encrypted with the random challenge ala ntlmssp. (This used to be commit 11f72a78e3a16bbb17b576d80b47a9eb818ee428) --- source3/nsswitch/wbinfo.c | 131 +++++++++++++++++++++++++++++++++----- source3/nsswitch/winbindd.c | 1 + source3/nsswitch/winbindd_nss.h | 9 +++ source3/nsswitch/winbindd_pam.c | 73 ++++++++++++++++++++- source3/nsswitch/winbindd_proto.h | 21 +++--- source3/nsswitch/winbindd_util.c | 1 + 6 files changed, 210 insertions(+), 26 deletions(-) (limited to 'source3/nsswitch') diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c index 9d3568417f..2e3991b97b 100644 --- a/source3/nsswitch/wbinfo.c +++ b/source3/nsswitch/wbinfo.c @@ -27,8 +27,9 @@ /* Prototypes from common.h */ -int winbindd_request(int req_type, struct winbindd_request *request, - struct winbindd_response *response); +enum nss_status winbindd_request(int req_type, + struct winbindd_request *request, + struct winbindd_response *response); /* List groups a user is a member of */ @@ -260,6 +261,85 @@ static BOOL wbinfo_lookupname(char *name) return True; } +/* Authenticate a user with a plaintext password */ + +static BOOL wbinfo_auth(char *username) +{ + struct winbindd_request request; + struct winbindd_response response; + enum winbindd_result result; + char *p; + + /* Send off request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + p = strchr(username, '%'); + + if (p) { + *p = 0; + fstrcpy(request.data.auth.user, username); + fstrcpy(request.data.auth.pass, p + 1); + *p = '%'; + } else + fstrcpy(request.data.auth.user, username); + + result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response); + + /* Display response */ + + printf("plaintext password authentication %s\n", + (result == WINBINDD_OK) ? "succeeded" : "failed"); + + return result == WINBINDD_OK; +} + +/* Authenticate a user with a challenge/response */ + +static BOOL wbinfo_auth_crap(char *username) +{ + struct winbindd_request request; + struct winbindd_response response; + enum winbindd_result result; + fstring pass; + char *p; + + /* Send off request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + p = strchr(username, '%'); + + if (p) { + *p = 0; + fstrcpy(request.data.auth_crap.user, username); + fstrcpy(pass, p + 1); + *p = '%'; + } else + fstrcpy(request.data.auth_crap.user, username); + + generate_random_buffer(request.data.auth_crap.chal, 8, False); + + SMBencrypt(pass, request.data.auth_crap.chal, + request.data.auth_crap.lm_resp); + SMBNTencrypt(pass, request.data.auth_crap.chal, + request.data.auth_crap.nt_resp); + + request.data.auth_crap.lm_resp_len = 24; + request.data.auth_crap.nt_resp_len = 24; + + result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response); + + /* Display response */ + + printf("challenge/response password authentication %s\n", + (result == WINBINDD_OK) ? "succeeded" : "failed"); + + return result == WINBINDD_OK; +} + /* Print domain users */ static BOOL print_domain_users(void) @@ -322,18 +402,20 @@ static BOOL print_domain_groups(void) static void usage(void) { - printf("Usage: wbinfo -ug | -n name | -sSY sid | -UG uid/gid | -tm\n"); - printf("\t-u\tlists all domain users\n"); - printf("\t-g\tlists all domain groups\n"); - printf("\t-n name\tconverts name to sid\n"); - printf("\t-s sid\tconverts sid to name\n"); - printf("\t-U uid\tconverts uid to sid\n"); - printf("\t-G gid\tconverts gid to sid\n"); - printf("\t-S sid\tconverts sid to uid\n"); - printf("\t-Y sid\tconverts sid to gid\n"); - printf("\t-t\tcheck shared secret\n"); - printf("\t-m\tlist trusted domains\n"); - printf("\t-r user\tget user groups\n"); + printf("Usage: wbinfo -ug | -n name | -sSY sid | -UG uid/gid | -tm " + "| -a user%%password\n"); + printf("\t-u\t\t\tlists all domain users\n"); + printf("\t-g\t\t\tlists all domain groups\n"); + printf("\t-n name\t\t\tconverts name to sid\n"); + printf("\t-s sid\t\t\tconverts sid to name\n"); + printf("\t-U uid\t\t\tconverts uid to sid\n"); + printf("\t-G gid\t\t\tconverts gid to sid\n"); + printf("\t-S sid\t\t\tconverts sid to uid\n"); + printf("\t-Y sid\t\t\tconverts sid to gid\n"); + printf("\t-t\t\t\tcheck shared secret\n"); + printf("\t-m\t\t\tlist trusted domains\n"); + printf("\t-r user\t\t\tget user groups\n"); + printf("\t-a user%%password\tauthenticate user\n"); } /* Main program */ @@ -371,7 +453,7 @@ int main(int argc, char **argv) return 1; } - while ((opt = getopt(argc, argv, "ugs:n:U:G:S:Y:tmr:")) != EOF) { + while ((opt = getopt(argc, argv, "ugs:n:U:G:S:Y:tmr:a:")) != EOF) { switch (opt) { case 'u': if (!print_domain_users()) { @@ -444,7 +526,26 @@ int main(int argc, char **argv) return 1; } break; + case 'a': { + BOOL got_error = False; + + if (!wbinfo_auth(optarg)) { + printf("Could not authenticate user %s with " + "plaintext password\n", optarg); + got_error = True; + } + + if (!wbinfo_auth_crap(optarg)) { + printf("Could not authenticate user %s with " + "challenge/response\n", optarg); + got_error = True; + } + + if (got_error) + return 1; + break; + } /* Invalid option */ default: diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index 0824b77294..4c82c9f3af 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -244,6 +244,7 @@ static struct dispatch_table dispatch_table[] = { /* PAM auth functions */ { WINBINDD_PAM_AUTH, winbindd_pam_auth }, + { WINBINDD_PAM_AUTH_CRAP, winbindd_pam_auth_crap }, { WINBINDD_PAM_CHAUTHTOK, winbindd_pam_chauthtok }, /* Enumeration functions */ diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index aedbaaf1fd..8e2eaf7ede 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -55,6 +55,7 @@ enum winbindd_cmd { /* PAM authenticate and password change */ WINBINDD_PAM_AUTH, + WINBINDD_PAM_AUTH_CRAP, WINBINDD_PAM_CHAUTHTOK, /* List various things */ @@ -99,6 +100,14 @@ struct winbindd_request { fstring user; fstring pass; } auth; /* pam_winbind auth module */ + struct { + char chal[8]; + fstring user; + fstring lm_resp; + uint16 lm_resp_len; + fstring nt_resp; + uint16 nt_resp_len; + } auth_crap; struct { fstring user; fstring oldpass; diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c index 4dc08c6086..e595bb0796 100644 --- a/source3/nsswitch/winbindd_pam.c +++ b/source3/nsswitch/winbindd_pam.c @@ -104,7 +104,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) generate_random_buffer( user_info.chal, 8, False); - if (state->request.data.auth.pass) { + if (state->request.data.auth.pass[0]) { SMBencrypt((uchar *)state->request.data.auth.pass, user_info.chal, local_lm_response); user_info.lm_resp.buffer = (uint8 *)local_lm_response; user_info.lm_resp.len = 24; @@ -136,6 +136,77 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) return result ? WINBINDD_OK : WINBINDD_ERROR; } +/* Challenge Response Authentication Protocol */ + +enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) +{ + BOOL result; + fstring name_domain, name_user; + unsigned char trust_passwd[16]; + time_t last_change_time; + auth_usersupplied_info user_info; + auth_serversupplied_info server_info; + AUTH_STR theirdomain, smb_username, wksta_name; + + DEBUG(3, ("[%5d]: pam auth crap %s\n", state->pid, + state->request.data.auth_crap.user)); + + /* Parse domain and username */ + + parse_domain_user(state->request.data.auth_crap.user, name_domain, + name_user); + + ZERO_STRUCT(user_info); + ZERO_STRUCT(theirdomain); + ZERO_STRUCT(smb_username); + ZERO_STRUCT(wksta_name); + + theirdomain.str = name_domain; + theirdomain.len = strlen(theirdomain.str); + + user_info.requested_domain = theirdomain; + user_info.domain = theirdomain; + + user_info.smb_username.str = name_user; + user_info.smb_username.len = strlen(name_user); + + user_info.requested_username.str = name_user; + user_info.requested_username.len = strlen(name_user); + + user_info.wksta_name.str = global_myname; + user_info.wksta_name.len = strlen(user_info.wksta_name.str); + + user_info.wksta_name = wksta_name; + + memcpy(user_info.chal, state->request.data.auth_crap.chal, 8); + + user_info.lm_resp.buffer = state->request.data.auth_crap.lm_resp; + user_info.nt_resp.buffer = state->request.data.auth_crap.nt_resp; + + user_info.lm_resp.len = 24; + user_info.nt_resp.len = 24; + + /* + * Get the machine account password for our primary domain + */ + + if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_passwd, &last_change_time)) + { + DEBUG(0, ("winbindd_pam_auth: could not fetch trust account password for domain %s\n", lp_workgroup())); + return WINBINDD_ERROR; + } + + /* So domain_client_validate() actually opens a new connection + for each authentication performed. This can theoretically + be optimised to use an already open IPC$ connection. */ + + result = (domain_client_validate(&user_info, &server_info, + server_state.controller, trust_passwd, + last_change_time) == NT_STATUS_NOPROBLEMO); + + return result ? WINBINDD_OK : WINBINDD_ERROR; +} + /* Change a user password */ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state) diff --git a/source3/nsswitch/winbindd_proto.h b/source3/nsswitch/winbindd_proto.h index 11a3bc4f86..3c61b1f872 100644 --- a/source3/nsswitch/winbindd_proto.h +++ b/source3/nsswitch/winbindd_proto.h @@ -3,12 +3,12 @@ /* This file is automatically generated with "make proto". DO NOT EDIT */ -/*The following definitions come from nsswitch/winbindd.c */ +/* The following definitions come from nsswitch/winbindd.c */ void winbindd_dump_status(void); int main(int argc, char **argv); -/*The following definitions come from nsswitch/winbindd_cache.c */ +/* The following definitions come from nsswitch/winbindd_cache.c */ void winbindd_cache_init(void); void winbindd_store_user_cache(char *domain, @@ -46,7 +46,7 @@ BOOL winbindd_fetch_gid_cache_entry(char *domain_name, gid_t gid, void winbindd_flush_cache(void); void winbindd_cache_dump_status(void); -/*The following definitions come from nsswitch/winbindd_group.c */ +/* The following definitions come from nsswitch/winbindd_group.c */ enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state *state); @@ -58,7 +58,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state); enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state); enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state); -/*The following definitions come from nsswitch/winbindd_idmap.c */ +/* The following definitions come from nsswitch/winbindd_idmap.c */ BOOL winbindd_idmap_get_uid_from_rid(char *domain_name, uint32 user_rid, uid_t *uid); @@ -73,21 +73,22 @@ BOOL winbindd_idmap_get_rid_from_gid(gid_t gid, uint32 *group_rid, BOOL winbindd_idmap_init(void); void winbindd_idmap_dump_status(void); -/*The following definitions come from nsswitch/winbindd_misc.c */ +/* The following definitions come from nsswitch/winbindd_misc.c */ BOOL _get_trust_account_password(char *domain, unsigned char *ret_pwd, - time_t *pass_last_set_time); + time_t *pass_last_set_time); enum winbindd_result winbindd_check_machine_acct( struct winbindd_cli_state *state); enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state *state); -/*The following definitions come from nsswitch/winbindd_pam.c */ +/* The following definitions come from nsswitch/winbindd_pam.c */ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) ; +enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) ; enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state); -/*The following definitions come from nsswitch/winbindd_sid.c */ +/* The following definitions come from nsswitch/winbindd_sid.c */ enum winbindd_result winbindd_lookupsid(struct winbindd_cli_state *state); enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state); @@ -96,7 +97,7 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state); enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state); enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state); -/*The following definitions come from nsswitch/winbindd_user.c */ +/* The following definitions come from nsswitch/winbindd_user.c */ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state) ; @@ -107,7 +108,7 @@ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state); enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state); enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state); -/*The following definitions come from nsswitch/winbindd_util.c */ +/* The following definitions come from nsswitch/winbindd_util.c */ void debug_conn_state(void); BOOL domain_handles_open(struct winbindd_domain *domain); diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index bdcf076acc..75ddb6bc09 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -788,6 +788,7 @@ static struct cmdstr_table cmdstr_table[] = { /* PAM auth functions */ { WINBINDD_PAM_AUTH, "pam auth" }, + { WINBINDD_PAM_AUTH_CRAP, "pam auth crap" }, { WINBINDD_PAM_CHAUTHTOK, "pam chauthtok" }, /* List things */ -- cgit