libwbclient: add wbcAuthenticateUserEx() function
authorStefan Metzmacher <metze@samba.org>
Thu, 24 Jan 2008 13:05:59 +0000 (14:05 +0100)
committerStefan Metzmacher <metze@samba.org>
Wed, 13 Feb 2008 12:30:15 +0000 (13:30 +0100)
This function will be used by auth_winbind.c.

metze
(This used to be commit 72af96a320a97ce1a730d6e33d01950123d6a97c)

source3/nsswitch/libwbclient/wbc_pam.c
source3/nsswitch/libwbclient/wbclient.c
source3/nsswitch/libwbclient/wbclient.h

index 7f7c7b814030bbfed373e2c1d6b18f2413a80151..e7bcdfe20d7af826a5fda704097611ce5479745e 100644 (file)
@@ -63,3 +63,303 @@ wbcErr wbcAuthenticateUser(const char *username,
 done:
        return wbc_status;
 }
+
+static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
+                                  const struct winbindd_response *resp,
+                                  struct wbcAuthUserInfo **_i)
+{
+       wbcErr wbc_status = WBC_ERR_SUCCESS;
+       struct wbcAuthUserInfo *i;
+       struct wbcDomainSid domain_sid;
+       char *p;
+       uint32_t sn = 0;
+       uint32_t j;
+
+       i = talloc(mem_ctx, struct wbcAuthUserInfo);
+       BAIL_ON_PTR_ERROR(i, wbc_status);
+
+       i->user_flags   = resp->data.auth.info3.user_flgs;
+
+       i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name);
+       BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
+       i->user_principal= NULL;
+       i->full_name    = talloc_strdup(i, resp->data.auth.info3.full_name);
+       BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
+       i->domain_name  = talloc_strdup(i, resp->data.auth.info3.logon_dom);
+       BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
+       i->dns_domain_name= NULL;
+
+       i->acct_flags   = resp->data.auth.info3.acct_flags;
+       memcpy(i->user_session_key,
+              resp->data.auth.user_session_key,
+              sizeof(i->user_session_key));
+       memcpy(i->lm_session_key,
+              resp->data.auth.first_8_lm_hash,
+              sizeof(i->lm_session_key));
+
+       i->logon_count          = resp->data.auth.info3.logon_count;
+       i->bad_password_count   = resp->data.auth.info3.bad_pw_count;
+
+       i->logon_time           = resp->data.auth.info3.logon_time;
+       i->logoff_time          = resp->data.auth.info3.logoff_time;
+       i->kickoff_time         = resp->data.auth.info3.kickoff_time;
+       i->pass_last_set_time   = resp->data.auth.info3.pass_last_set_time;
+       i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
+       i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
+
+       i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv);
+       BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
+       i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script);
+       BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
+       i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path);
+       BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
+       i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir);
+       BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
+       i->home_drive   = talloc_strdup(i, resp->data.auth.info3.dir_drive);
+       BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
+
+       i->num_sids     = 2;
+       i->num_sids     += resp->data.auth.info3.num_groups;
+       i->num_sids     += resp->data.auth.info3.num_other_sids;
+
+       i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
+       BAIL_ON_PTR_ERROR(i->sids, wbc_status);
+
+       wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
+                                   &domain_sid);
+       BAIL_ON_WBC_ERROR(wbc_status);
+
+#define _SID_COMPOSE(s, d, r, a) { \
+       (s).sid = d; \
+       if ((s).sid.num_auths < MAXSUBAUTHS) { \
+               (s).sid.sub_auths[(s).sid.num_auths++] = r; \
+       } else { \
+               wbc_status = WBC_ERR_INVALID_SID; \
+               BAIL_ON_WBC_ERROR(wbc_status); \
+       } \
+       (s).attributes = a; \
+} while (0)
+
+       sn = 0;
+       _SID_COMPOSE(i->sids[sn], domain_sid,
+                    resp->data.auth.info3.user_rid,
+                    0);
+       sn++;
+       _SID_COMPOSE(i->sids[sn], domain_sid,
+                    resp->data.auth.info3.group_rid,
+                    0);
+       sn++;
+
+       p = resp->extra_data.data;
+       if (!p) {
+               wbc_status = WBC_INVALID_RESPONSE;
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+
+       for (j=0; j < resp->data.auth.info3.num_groups; j++) {
+               uint32_t rid;
+               uint32_t attrs;
+               int ret;
+               char *s = p;
+               char *e = strchr(p, '\n');
+               if (!e) {
+                       wbc_status = WBC_INVALID_RESPONSE;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+               e[0] = '\0';
+               p = &e[1];
+
+               ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
+               if (ret != 2) {
+                       wbc_status = WBC_INVALID_RESPONSE;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               _SID_COMPOSE(i->sids[sn], domain_sid,
+                            rid, attrs);
+               sn++;
+       }
+
+       for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
+               uint32_t attrs;
+               int ret;
+               char *s = p;
+               char *a;
+               char *e = strchr(p, '\n');
+               if (!e) {
+                       wbc_status = WBC_INVALID_RESPONSE;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+               e[0] = '\0';
+               p = &e[1];
+
+               e = strchr(s, ':');
+               if (!e) {
+                       wbc_status = WBC_INVALID_RESPONSE;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+               e[0] = '\0';
+               a = &e[1];
+
+               ret = sscanf(a, "0x%08X",
+                            &attrs);
+               if (ret != 1) {
+                       wbc_status = WBC_INVALID_RESPONSE;
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
+               BAIL_ON_WBC_ERROR(wbc_status);
+
+               i->sids[sn].attributes = attrs;
+               sn++;
+       }
+
+       i->num_sids = sn;
+
+       *_i = i;
+       i = NULL;
+done:
+       talloc_free(i);
+       return wbc_status;
+}
+
+static wbcErr wbc_create_error_info(TALLOC_CTX *mem_ctx,
+                                 const struct winbindd_response *resp,
+                                 struct wbcAuthErrorInfo **_e)
+{
+       wbcErr wbc_status = WBC_ERR_SUCCESS;
+       struct wbcAuthErrorInfo *e;
+
+       e = talloc(mem_ctx, struct wbcAuthErrorInfo);
+       BAIL_ON_PTR_ERROR(e, wbc_status);
+
+       e->nt_status = resp->data.auth.nt_status;
+       e->pam_error = resp->data.auth.pam_error;
+       e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
+       BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
+
+       e->display_string = talloc_strdup(e, resp->data.auth.error_string);
+       BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
+
+       *_e = e;
+       e = NULL;
+
+done:
+       talloc_free(e);
+       return wbc_status;
+}
+
+/** @brief Authenticate with more detailed information
+ *
+ * @param params       Input parameters, only WBC_AUTH_USER_LEVEL_RESPONSE
+ *                     is supported yet
+ * @param info         Output details on WBC_ERR_SUCCESS
+ * @param error        Output details on WBC_ERR_AUTH_ERROR
+ *
+ * @return #wbcErr
+ **/
+
+wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
+                            struct wbcAuthUserInfo **info,
+                            struct wbcAuthErrorInfo **error)
+{
+       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+       int cmd;
+       struct winbindd_request request;
+       struct winbindd_response response;
+
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       if (error) {
+               *error = NULL;
+       }
+
+       if (!params) {
+               wbc_status = WBC_ERR_INVALID_PARAM;
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+
+       /* Initialize request */
+
+       switch (params->level) {
+       case WBC_AUTH_USER_LEVEL_PLAIN:
+               wbc_status = WBC_ERR_NOT_IMPLEMENTED;
+               BAIL_ON_WBC_ERROR(wbc_status);
+               break;
+
+       case WBC_AUTH_USER_LEVEL_HASH:
+               wbc_status = WBC_ERR_NOT_IMPLEMENTED;
+               BAIL_ON_WBC_ERROR(wbc_status);
+               break;
+
+       case WBC_AUTH_USER_LEVEL_RESPONSE:
+               cmd = WINBINDD_PAM_AUTH_CRAP;
+               request.flags = WBFLAG_PAM_INFO3_TEXT |
+                               WBFLAG_PAM_USER_SESSION_KEY |
+                               WBFLAG_PAM_LMKEY;
+
+               strncpy(request.data.auth_crap.user,
+                       params->account_name,
+                       sizeof(request.data.auth_crap.user)-1);
+               strncpy(request.data.auth_crap.domain,
+                       params->domain_name,
+                       sizeof(request.data.auth_crap.domain)-1);
+               if (params->workstation_name) {
+                       strncpy(request.data.auth_crap.workstation,
+                               params->workstation_name,
+                               sizeof(request.data.auth_crap.workstation)-1);
+               }
+
+               request.data.auth_crap.logon_parameters =
+                               params->parameter_control;
+
+               memcpy(request.data.auth_crap.chal,
+                      params->password.response.challenge,
+                      sizeof(request.data.auth_crap.chal));
+
+               request.data.auth_crap.lm_resp_len =
+                               MIN(params->password.response.lm_length,
+                                   sizeof(request.data.auth_crap.lm_resp));
+               request.data.auth_crap.nt_resp_len =
+                               MIN(params->password.response.nt_length,
+                                   sizeof(request.data.auth_crap.nt_resp));
+               memcpy(request.data.auth_crap.lm_resp,
+                      params->password.response.lm_data,
+                      request.data.auth_crap.lm_resp_len);
+               memcpy(request.data.auth_crap.nt_resp,
+                      params->password.response.nt_data,
+                      request.data.auth_crap.nt_resp_len);
+
+               break;
+       }
+
+       wbc_status = wbcRequestResponse(cmd,
+                                       &request,
+                                       &response);
+       if (response.data.auth.nt_status != 0) {
+               if (error) {
+                       wbc_status = wbc_create_error_info(NULL,
+                                                          &response,
+                                                          error);
+                       BAIL_ON_WBC_ERROR(wbc_status);
+               }
+
+               wbc_status = WBC_ERR_AUTH_ERROR;
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+       BAIL_ON_WBC_ERROR(wbc_status);
+
+       if (info) {
+               wbc_status = wbc_create_auth_info(NULL,
+                                                 &response,
+                                                 info);
+               BAIL_ON_WBC_ERROR(wbc_status);
+       }
+
+done:
+
+       return wbc_status;
+}
index 5aad378ad0e2742ef42497cba946a3acd00e9b46..e17296283f02d355396c91e03e86c7eb68ef4007 100644 (file)
@@ -110,6 +110,8 @@ const char *wbcErrorString(wbcErr error)
                return "WBC_INVALID_RESPONSE";
        case WBC_ERR_NSS_ERROR:
                return "WBC_ERR_NSS_ERROR";
+       case WBC_ERR_AUTH_ERROR:
+               return "WBC_ERR_AUTH_ERROR";
        }
 
        return "unknown wbcErr value";
index ef9e3557da4457a3585db1e1475a544db564a9f2..c01db9618d9ae3b53ac2b419d003bbe36f871d69 100644 (file)
@@ -41,7 +41,8 @@ enum _wbcErrType {
        WBC_ERR_WINBIND_NOT_AVAILABLE,   /**< Winbind daemon is not available **/
        WBC_ERR_DOMAIN_NOT_FOUND,        /**< Domain is not trusted or cannot be found **/
        WBC_INVALID_RESPONSE,        /**< Winbind returned an invalid response **/
-       WBC_ERR_NSS_ERROR            /**< NSS_STATUS error **/
+       WBC_ERR_NSS_ERROR,            /**< NSS_STATUS error **/
+       WBC_ERR_AUTH_ERROR        /**< Authentication failed **/
 };
 
 typedef enum _wbcErrType wbcErr;
@@ -87,6 +88,25 @@ enum wbcSidType {
        WBC_SID_NAME_COMPUTER=9
 };
 
+/**
+ * @brief Security Identifier with attributes
+ **/
+
+struct wbcSidWithAttr {
+       struct wbcDomainSid sid;
+       uint32_t attributes;
+};
+
+/* wbcSidWithAttr->attributes */
+
+#define WBC_SID_ATTR_GROUP_MANDATORY           0x00000001
+#define WBC_SID_ATTR_GROUP_ENABLED_BY_DEFAULT  0x00000002
+#define WBC_SID_ATTR_GROUP_ENABLED             0x00000004
+#define WBC_SID_ATTR_GROUP_OWNER               0x00000008
+#define WBC_SID_ATTR_GROUP_USEFOR_DENY_ONLY    0x00000010
+#define WBC_SID_ATTR_GROUP_RESOURCE            0x20000000
+#define WBC_SID_ATTR_GROUP_LOGON_ID            0xC0000000
+
 /**
  * @brief Domain Information
  **/
@@ -104,6 +124,140 @@ struct wbcDomainInfo {
 #define WBC_DOMINFO_AD                0x00000002
 #define WBC_DOMINFO_PRIMARY           0x00000004
 
+/**
+ * @brief Auth User Parameters
+ **/
+
+struct wbcAuthUserParams {
+       const char *account_name;
+       const char *domain_name;
+       const char *workstation_name;
+
+       uint32_t flags;
+
+       uint32_t parameter_control;
+
+       enum wbcAuthUserLevel {
+               WBC_AUTH_USER_LEVEL_PLAIN = 1,
+               WBC_AUTH_USER_LEVEL_HASH = 2,
+               WBC_AUTH_USER_LEVEL_RESPONSE = 3
+       } level;
+       union {
+               const char *plaintext;
+               struct {
+                       uint8_t nt_hash[16];
+                       uint8_t lm_hash[16];
+               } hash;
+               struct {
+                       uint8_t challenge[8];
+                       uint32_t nt_length;
+                       uint8_t *nt_data;
+                       uint32_t lm_length;
+                       uint8_t *lm_data;
+               } response;
+       } password;
+};
+
+/* wbcAuthUserParams->parameter_control */
+
+#define WBC_MSV1_0_CLEARTEXT_PASSWORD_ALLOWED          0x00000002
+#define WBC_MSV1_0_UPDATE_LOGON_STATISTICS             0x00000004
+#define WBC_MSV1_0_RETURN_USER_PARAMETERS              0x00000008
+#define WBC_MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT          0x00000020
+#define WBC_MSV1_0_RETURN_PROFILE_PATH                 0x00000200
+#define WBC_MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT     0x00000800
+
+/* wbcAuthUserParams->flags */
+
+#define WBC_AUTH_PARAM_FLAGS_INTERACTIVE_LOGON         0x00000001
+
+/**
+ * @brief Auth User Information
+ *
+ * Some of the strings are maybe NULL
+ **/
+
+struct wbcAuthUserInfo {
+       uint32_t user_flags;
+
+       char *account_name;
+       char *user_principal;
+       char *full_name;
+       char *domain_name;
+       char *dns_domain_name;
+
+       uint32_t acct_flags;
+       uint8_t user_session_key[16];
+       uint8_t lm_session_key[8];
+
+       uint16_t logon_count;
+       uint16_t bad_password_count;
+
+       uint64_t logon_time;
+       uint64_t logoff_time;
+       uint64_t kickoff_time;
+       uint64_t pass_last_set_time;
+       uint64_t pass_can_change_time;
+       uint64_t pass_must_change_time;
+
+       char *logon_server;
+       char *logon_script;
+       char *profile_path;
+       char *home_directory;
+       char *home_drive;
+
+       /*
+        * the 1st one is the account sid
+        * the 2nd one is the primary_group sid
+        * followed by the rest of the groups
+        */
+       uint32_t num_sids;
+       struct wbcSidWithAttr *sids;
+};
+
+/* wbcAuthUserInfo->user_flags */
+
+#define WBC_AUTH_USER_INFO_GUEST                       0x00000001
+#define WBC_AUTH_USER_INFO_NOENCRYPTION                        0x00000002
+#define WBC_AUTH_USER_INFO_CACHED_ACCOUNT              0x00000004
+#define WBC_AUTH_USER_INFO_USED_LM_PASSWORD            0x00000008
+#define WBC_AUTH_USER_INFO_EXTRA_SIDS                  0x00000020
+#define WBC_AUTH_USER_INFO_SUBAUTH_SESSION_KEY         0x00000040
+#define WBC_AUTH_USER_INFO_SERVER_TRUST_ACCOUNT                0x00000080
+#define WBC_AUTH_USER_INFO_NTLMV2_ENABLED              0x00000100
+#define WBC_AUTH_USER_INFO_RESOURCE_GROUPS             0x00000200
+#define WBC_AUTH_USER_INFO_PROFILE_PATH_RETURNED       0x00000400
+#define WBC_AUTH_USER_INFO_GRACE_LOGON                 0x01000000
+
+/* wbcAuthUserInfo->acct_flags */
+
+#define WBC_ACB_DISABLED                       0x00000001 /* 1 User account disabled */
+#define WBC_ACB_HOMDIRREQ                      0x00000002 /* 1 Home directory required */
+#define WBC_ACB_PWNOTREQ                       0x00000004 /* 1 User password not required */
+#define WBC_ACB_TEMPDUP                                0x00000008 /* 1 Temporary duplicate account */
+#define WBC_ACB_NORMAL                         0x00000010 /* 1 Normal user account */
+#define WBC_ACB_MNS                            0x00000020 /* 1 MNS logon user account */
+#define WBC_ACB_DOMTRUST                       0x00000040 /* 1 Interdomain trust account */
+#define WBC_ACB_WSTRUST                                0x00000080 /* 1 Workstation trust account */
+#define WBC_ACB_SVRTRUST                       0x00000100 /* 1 Server trust account */
+#define WBC_ACB_PWNOEXP                                0x00000200 /* 1 User password does not expire */
+#define WBC_ACB_AUTOLOCK                       0x00000400 /* 1 Account auto locked */
+#define WBC_ACB_ENC_TXT_PWD_ALLOWED            0x00000800 /* 1 Encryped text password is allowed */
+#define WBC_ACB_SMARTCARD_REQUIRED             0x00001000 /* 1 Smart Card required */
+#define WBC_ACB_TRUSTED_FOR_DELEGATION         0x00002000 /* 1 Trusted for Delegation */
+#define WBC_ACB_NOT_DELEGATED                  0x00004000 /* 1 Not delegated */
+#define WBC_ACB_USE_DES_KEY_ONLY               0x00008000 /* 1 Use DES key only */
+#define WBC_ACB_DONT_REQUIRE_PREAUTH           0x00010000 /* 1 Preauth not required */
+#define WBC_ACB_PW_EXPIRED                     0x00020000 /* 1 Password Expired */
+#define WBC_ACB_NO_AUTH_DATA_REQD              0x00080000   /* 1 = No authorization data required */
+
+struct wbcAuthErrorInfo {
+       uint32_t nt_status;
+       char *nt_string;
+       int32_t pam_error;
+       char *display_string;
+};
+
 /*
  * Memory Management
  */
@@ -205,5 +359,8 @@ wbcErr wbcDomainSequenceNumbers(void);
 wbcErr wbcAuthenticateUser(const char *username,
                           const char *password);
 
+wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
+                            struct wbcAuthUserInfo **info,
+                            struct wbcAuthErrorInfo **error);
 
 #endif      /* _WBCLIENT_H */