| 1 | /*
 | 
|---|
| 2 |    Unix SMB/CIFS implementation.
 | 
|---|
| 3 |    Authentication utility functions
 | 
|---|
| 4 |    Copyright (C) Volker Lendecke 2010
 | 
|---|
| 5 | 
 | 
|---|
| 6 |    This program is free software; you can redistribute it and/or modify
 | 
|---|
| 7 |    it under the terms of the GNU General Public License as published by
 | 
|---|
| 8 |    the Free Software Foundation; either version 3 of the License, or
 | 
|---|
| 9 |    (at your option) any later version.
 | 
|---|
| 10 | 
 | 
|---|
| 11 |    This program is distributed in the hope that it will be useful,
 | 
|---|
| 12 |    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 13 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 14 |    GNU General Public License for more details.
 | 
|---|
| 15 | 
 | 
|---|
| 16 |    You should have received a copy of the GNU General Public License
 | 
|---|
| 17 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 18 | */
 | 
|---|
| 19 | 
 | 
|---|
| 20 | #include "includes.h"
 | 
|---|
| 21 | #include "auth.h"
 | 
|---|
| 22 | #include "../lib/crypto/arcfour.h"
 | 
|---|
| 23 | #include "../librpc/gen_ndr/netlogon.h"
 | 
|---|
| 24 | #include "../libcli/security/security.h"
 | 
|---|
| 25 | #include "rpc_client/util_netlogon.h"
 | 
|---|
| 26 | #include "nsswitch/libwbclient/wbclient.h"
 | 
|---|
| 27 | #include "passdb.h"
 | 
|---|
| 28 | 
 | 
|---|
| 29 | #undef DBGC_CLASS
 | 
|---|
| 30 | #define DBGC_CLASS DBGC_AUTH
 | 
|---|
| 31 | 
 | 
|---|
| 32 | /* FIXME: do we really still need this ? */
 | 
|---|
| 33 | static int server_info_dtor(struct auth_serversupplied_info *server_info)
 | 
|---|
| 34 | {
 | 
|---|
| 35 |         TALLOC_FREE(server_info->info3);
 | 
|---|
| 36 |         ZERO_STRUCTP(server_info);
 | 
|---|
| 37 |         return 0;
 | 
|---|
| 38 | }
 | 
|---|
| 39 | 
 | 
|---|
| 40 | /***************************************************************************
 | 
|---|
| 41 |  Make a server_info struct. Free with TALLOC_FREE().
 | 
|---|
| 42 | ***************************************************************************/
 | 
|---|
| 43 | 
 | 
|---|
| 44 | struct auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx)
 | 
|---|
| 45 | {
 | 
|---|
| 46 |         struct auth_serversupplied_info *result;
 | 
|---|
| 47 | 
 | 
|---|
| 48 |         result = TALLOC_ZERO_P(mem_ctx, struct auth_serversupplied_info);
 | 
|---|
| 49 |         if (result == NULL) {
 | 
|---|
| 50 |                 DEBUG(0, ("talloc failed\n"));
 | 
|---|
| 51 |                 return NULL;
 | 
|---|
| 52 |         }
 | 
|---|
| 53 | 
 | 
|---|
| 54 |         talloc_set_destructor(result, server_info_dtor);
 | 
|---|
| 55 | 
 | 
|---|
| 56 |         /* Initialise the uid and gid values to something non-zero
 | 
|---|
| 57 |            which may save us from giving away root access if there
 | 
|---|
| 58 |            is a bug in allocating these fields. */
 | 
|---|
| 59 | 
 | 
|---|
| 60 |         result->utok.uid = -1;
 | 
|---|
| 61 |         result->utok.gid = -1;
 | 
|---|
| 62 | 
 | 
|---|
| 63 |         return result;
 | 
|---|
| 64 | }
 | 
|---|
| 65 | 
 | 
|---|
| 66 | /****************************************************************************
 | 
|---|
| 67 |  inits a netr_SamInfo2 structure from an auth_serversupplied_info. sam2 must
 | 
|---|
| 68 |  already be initialized and is used as the talloc parent for its members.
 | 
|---|
| 69 | *****************************************************************************/
 | 
|---|
| 70 | 
 | 
|---|
| 71 | NTSTATUS serverinfo_to_SamInfo2(struct auth_serversupplied_info *server_info,
 | 
|---|
| 72 |                                 uint8_t *pipe_session_key,
 | 
|---|
| 73 |                                 size_t pipe_session_key_len,
 | 
|---|
| 74 |                                 struct netr_SamInfo2 *sam2)
 | 
|---|
| 75 | {
 | 
|---|
| 76 |         struct netr_SamInfo3 *info3;
 | 
|---|
| 77 | 
 | 
|---|
| 78 |         info3 = copy_netr_SamInfo3(sam2, server_info->info3);
 | 
|---|
| 79 |         if (!info3) {
 | 
|---|
| 80 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 81 |         }
 | 
|---|
| 82 | 
 | 
|---|
| 83 |         if (server_info->user_session_key.length) {
 | 
|---|
| 84 |                 memcpy(info3->base.key.key,
 | 
|---|
| 85 |                        server_info->user_session_key.data,
 | 
|---|
| 86 |                        MIN(sizeof(info3->base.key.key),
 | 
|---|
| 87 |                            server_info->user_session_key.length));
 | 
|---|
| 88 |                 if (pipe_session_key) {
 | 
|---|
| 89 |                         arcfour_crypt(info3->base.key.key,
 | 
|---|
| 90 |                                       pipe_session_key, 16);
 | 
|---|
| 91 |                 }
 | 
|---|
| 92 |         }
 | 
|---|
| 93 |         if (server_info->lm_session_key.length) {
 | 
|---|
| 94 |                 memcpy(info3->base.LMSessKey.key,
 | 
|---|
| 95 |                        server_info->lm_session_key.data,
 | 
|---|
| 96 |                        MIN(sizeof(info3->base.LMSessKey.key),
 | 
|---|
| 97 |                            server_info->lm_session_key.length));
 | 
|---|
| 98 |                 if (pipe_session_key) {
 | 
|---|
| 99 |                         arcfour_crypt(info3->base.LMSessKey.key,
 | 
|---|
| 100 |                                       pipe_session_key, 8);
 | 
|---|
| 101 |                 }
 | 
|---|
| 102 |         }
 | 
|---|
| 103 | 
 | 
|---|
| 104 |         sam2->base = info3->base;
 | 
|---|
| 105 | 
 | 
|---|
| 106 |         return NT_STATUS_OK;
 | 
|---|
| 107 | }
 | 
|---|
| 108 | 
 | 
|---|
| 109 | /****************************************************************************
 | 
|---|
| 110 |  inits a netr_SamInfo3 structure from an auth_serversupplied_info. sam3 must
 | 
|---|
| 111 |  already be initialized and is used as the talloc parent for its members.
 | 
|---|
| 112 | *****************************************************************************/
 | 
|---|
| 113 | 
 | 
|---|
| 114 | NTSTATUS serverinfo_to_SamInfo3(const struct auth_serversupplied_info *server_info,
 | 
|---|
| 115 |                                 uint8_t *pipe_session_key,
 | 
|---|
| 116 |                                 size_t pipe_session_key_len,
 | 
|---|
| 117 |                                 struct netr_SamInfo3 *sam3)
 | 
|---|
| 118 | {
 | 
|---|
| 119 |         struct netr_SamInfo3 *info3;
 | 
|---|
| 120 | 
 | 
|---|
| 121 |         info3 = copy_netr_SamInfo3(sam3, server_info->info3);
 | 
|---|
| 122 |         if (!info3) {
 | 
|---|
| 123 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 124 |         }
 | 
|---|
| 125 | 
 | 
|---|
| 126 |         if (server_info->user_session_key.length) {
 | 
|---|
| 127 |                 memcpy(info3->base.key.key,
 | 
|---|
| 128 |                        server_info->user_session_key.data,
 | 
|---|
| 129 |                        MIN(sizeof(info3->base.key.key),
 | 
|---|
| 130 |                            server_info->user_session_key.length));
 | 
|---|
| 131 |                 if (pipe_session_key) {
 | 
|---|
| 132 |                         arcfour_crypt(info3->base.key.key,
 | 
|---|
| 133 |                                       pipe_session_key, 16);
 | 
|---|
| 134 |                 }
 | 
|---|
| 135 |         }
 | 
|---|
| 136 |         if (server_info->lm_session_key.length) {
 | 
|---|
| 137 |                 memcpy(info3->base.LMSessKey.key,
 | 
|---|
| 138 |                        server_info->lm_session_key.data,
 | 
|---|
| 139 |                        MIN(sizeof(info3->base.LMSessKey.key),
 | 
|---|
| 140 |                            server_info->lm_session_key.length));
 | 
|---|
| 141 |                 if (pipe_session_key) {
 | 
|---|
| 142 |                         arcfour_crypt(info3->base.LMSessKey.key,
 | 
|---|
| 143 |                                       pipe_session_key, 8);
 | 
|---|
| 144 |                 }
 | 
|---|
| 145 |         }
 | 
|---|
| 146 | 
 | 
|---|
| 147 |         sam3->base = info3->base;
 | 
|---|
| 148 | 
 | 
|---|
| 149 |         sam3->sidcount          = 0;
 | 
|---|
| 150 |         sam3->sids              = NULL;
 | 
|---|
| 151 | 
 | 
|---|
| 152 |         return NT_STATUS_OK;
 | 
|---|
| 153 | }
 | 
|---|
| 154 | 
 | 
|---|
| 155 | /****************************************************************************
 | 
|---|
| 156 |  inits a netr_SamInfo6 structure from an auth_serversupplied_info. sam6 must
 | 
|---|
| 157 |  already be initialized and is used as the talloc parent for its members.
 | 
|---|
| 158 | *****************************************************************************/
 | 
|---|
| 159 | 
 | 
|---|
| 160 | NTSTATUS serverinfo_to_SamInfo6(struct auth_serversupplied_info *server_info,
 | 
|---|
| 161 |                                 uint8_t *pipe_session_key,
 | 
|---|
| 162 |                                 size_t pipe_session_key_len,
 | 
|---|
| 163 |                                 struct netr_SamInfo6 *sam6)
 | 
|---|
| 164 | {
 | 
|---|
| 165 |         struct pdb_domain_info *dominfo;
 | 
|---|
| 166 |         struct netr_SamInfo3 *info3;
 | 
|---|
| 167 | 
 | 
|---|
| 168 |         if ((pdb_capabilities() & PDB_CAP_ADS) == 0) {
 | 
|---|
| 169 |                 DEBUG(10,("Not adding validation info level 6 "
 | 
|---|
| 170 |                            "without ADS passdb backend\n"));
 | 
|---|
| 171 |                 return NT_STATUS_INVALID_INFO_CLASS;
 | 
|---|
| 172 |         }
 | 
|---|
| 173 | 
 | 
|---|
| 174 |         dominfo = pdb_get_domain_info(sam6);
 | 
|---|
| 175 |         if (dominfo == NULL) {
 | 
|---|
| 176 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 177 |         }
 | 
|---|
| 178 | 
 | 
|---|
| 179 |         info3 = copy_netr_SamInfo3(sam6, server_info->info3);
 | 
|---|
| 180 |         if (!info3) {
 | 
|---|
| 181 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 182 |         }
 | 
|---|
| 183 | 
 | 
|---|
| 184 |         if (server_info->user_session_key.length) {
 | 
|---|
| 185 |                 memcpy(info3->base.key.key,
 | 
|---|
| 186 |                        server_info->user_session_key.data,
 | 
|---|
| 187 |                        MIN(sizeof(info3->base.key.key),
 | 
|---|
| 188 |                            server_info->user_session_key.length));
 | 
|---|
| 189 |                 if (pipe_session_key) {
 | 
|---|
| 190 |                         arcfour_crypt(info3->base.key.key,
 | 
|---|
| 191 |                                       pipe_session_key, 16);
 | 
|---|
| 192 |                 }
 | 
|---|
| 193 |         }
 | 
|---|
| 194 |         if (server_info->lm_session_key.length) {
 | 
|---|
| 195 |                 memcpy(info3->base.LMSessKey.key,
 | 
|---|
| 196 |                        server_info->lm_session_key.data,
 | 
|---|
| 197 |                        MIN(sizeof(info3->base.LMSessKey.key),
 | 
|---|
| 198 |                            server_info->lm_session_key.length));
 | 
|---|
| 199 |                 if (pipe_session_key) {
 | 
|---|
| 200 |                         arcfour_crypt(info3->base.LMSessKey.key,
 | 
|---|
| 201 |                                       pipe_session_key, 8);
 | 
|---|
| 202 |                 }
 | 
|---|
| 203 |         }
 | 
|---|
| 204 | 
 | 
|---|
| 205 |         sam6->base = info3->base;
 | 
|---|
| 206 | 
 | 
|---|
| 207 |         sam6->sidcount          = 0;
 | 
|---|
| 208 |         sam6->sids              = NULL;
 | 
|---|
| 209 | 
 | 
|---|
| 210 |         sam6->dns_domainname.string = talloc_strdup(sam6, dominfo->dns_domain);
 | 
|---|
| 211 |         if (sam6->dns_domainname.string == NULL) {
 | 
|---|
| 212 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 213 |         }
 | 
|---|
| 214 | 
 | 
|---|
| 215 |         sam6->principle.string  = talloc_asprintf(sam6, "%s@%s",
 | 
|---|
| 216 |                                                   sam6->base.account_name.string,
 | 
|---|
| 217 |                                                   sam6->dns_domainname.string);
 | 
|---|
| 218 |         if (sam6->principle.string == NULL) {
 | 
|---|
| 219 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 220 |         }
 | 
|---|
| 221 | 
 | 
|---|
| 222 |         return NT_STATUS_OK;
 | 
|---|
| 223 | }
 | 
|---|
| 224 | 
 | 
|---|
| 225 | static NTSTATUS append_netr_SidAttr(TALLOC_CTX *mem_ctx,
 | 
|---|
| 226 |                                     struct netr_SidAttr **sids,
 | 
|---|
| 227 |                                     uint32_t *count,
 | 
|---|
| 228 |                                     const struct dom_sid2 *asid,
 | 
|---|
| 229 |                                     uint32_t attributes)
 | 
|---|
| 230 | {
 | 
|---|
| 231 |         uint32_t t = *count;
 | 
|---|
| 232 | 
 | 
|---|
| 233 |         *sids = talloc_realloc(mem_ctx, *sids, struct netr_SidAttr, t + 1);
 | 
|---|
| 234 |         if (*sids == NULL) {
 | 
|---|
| 235 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 236 |         }
 | 
|---|
| 237 |         (*sids)[t].sid = dom_sid_dup(*sids, asid);
 | 
|---|
| 238 |         if ((*sids)[t].sid == NULL) {
 | 
|---|
| 239 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 240 |         }
 | 
|---|
| 241 |         (*sids)[t].attributes = attributes;
 | 
|---|
| 242 |         *count = t + 1;
 | 
|---|
| 243 | 
 | 
|---|
| 244 |         return NT_STATUS_OK;
 | 
|---|
| 245 | }
 | 
|---|
| 246 | 
 | 
|---|
| 247 | /* Fills the samr_RidWithAttributeArray with the provided sids.
 | 
|---|
| 248 |  * If it happens that we have additional groups that do not belong
 | 
|---|
| 249 |  * to the domain, add their sids as extra sids */
 | 
|---|
| 250 | static NTSTATUS group_sids_to_info3(struct netr_SamInfo3 *info3,
 | 
|---|
| 251 |                                     const struct dom_sid *sids,
 | 
|---|
| 252 |                                     size_t num_sids)
 | 
|---|
| 253 | {
 | 
|---|
| 254 |         uint32_t attributes = SE_GROUP_MANDATORY |
 | 
|---|
| 255 |                                 SE_GROUP_ENABLED_BY_DEFAULT |
 | 
|---|
| 256 |                                 SE_GROUP_ENABLED;
 | 
|---|
| 257 |         struct samr_RidWithAttributeArray *groups;
 | 
|---|
| 258 |         struct dom_sid *domain_sid;
 | 
|---|
| 259 |         unsigned int i;
 | 
|---|
| 260 |         NTSTATUS status;
 | 
|---|
| 261 |         uint32_t rid;
 | 
|---|
| 262 |         bool ok;
 | 
|---|
| 263 | 
 | 
|---|
| 264 |         domain_sid = info3->base.domain_sid;
 | 
|---|
| 265 |         groups = &info3->base.groups;
 | 
|---|
| 266 | 
 | 
|---|
| 267 |         groups->rids = talloc_array(info3,
 | 
|---|
| 268 |                                     struct samr_RidWithAttribute, num_sids);
 | 
|---|
| 269 |         if (!groups->rids) {
 | 
|---|
| 270 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 271 |         }
 | 
|---|
| 272 | 
 | 
|---|
| 273 |         for (i = 0; i < num_sids; i++) {
 | 
|---|
| 274 |                 ok = sid_peek_check_rid(domain_sid, &sids[i], &rid);
 | 
|---|
| 275 |                 if (ok) {
 | 
|---|
| 276 |                         /* store domain group rid */
 | 
|---|
| 277 |                         groups->rids[groups->count].rid = rid;
 | 
|---|
| 278 |                         groups->rids[groups->count].attributes = attributes;
 | 
|---|
| 279 |                         groups->count++;
 | 
|---|
| 280 |                         continue;
 | 
|---|
| 281 |                 }
 | 
|---|
| 282 | 
 | 
|---|
| 283 |                 /* if this wasn't a domain sid, add it as extra sid */
 | 
|---|
| 284 |                 status = append_netr_SidAttr(info3, &info3->sids,
 | 
|---|
| 285 |                                              &info3->sidcount,
 | 
|---|
| 286 |                                              &sids[i], attributes);
 | 
|---|
| 287 |                 if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 288 |                         return status;
 | 
|---|
| 289 |                 }
 | 
|---|
| 290 |         }
 | 
|---|
| 291 | 
 | 
|---|
| 292 |         return NT_STATUS_OK;
 | 
|---|
| 293 | }
 | 
|---|
| 294 | 
 | 
|---|
| 295 | #define RET_NOMEM(ptr) do { \
 | 
|---|
| 296 |         if (!ptr) { \
 | 
|---|
| 297 |                 TALLOC_FREE(info3); \
 | 
|---|
| 298 |                 return NT_STATUS_NO_MEMORY; \
 | 
|---|
| 299 |         } } while(0)
 | 
|---|
| 300 | 
 | 
|---|
| 301 | NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
 | 
|---|
| 302 |                           struct samu *samu,
 | 
|---|
| 303 |                           const char *login_server,
 | 
|---|
| 304 |                           struct netr_SamInfo3 **_info3,
 | 
|---|
| 305 |                           struct extra_auth_info *extra)
 | 
|---|
| 306 | {
 | 
|---|
| 307 |         struct netr_SamInfo3 *info3;
 | 
|---|
| 308 |         const struct dom_sid *user_sid;
 | 
|---|
| 309 |         const struct dom_sid *group_sid;
 | 
|---|
| 310 |         struct dom_sid domain_sid;
 | 
|---|
| 311 |         struct dom_sid *group_sids;
 | 
|---|
| 312 |         uint32_t num_group_sids = 0;
 | 
|---|
| 313 |         const char *tmp;
 | 
|---|
| 314 |         gid_t *gids;
 | 
|---|
| 315 |         NTSTATUS status;
 | 
|---|
| 316 |         bool ok;
 | 
|---|
| 317 | 
 | 
|---|
| 318 |         user_sid = pdb_get_user_sid(samu);
 | 
|---|
| 319 |         group_sid = pdb_get_group_sid(samu);
 | 
|---|
| 320 | 
 | 
|---|
| 321 |         if (!user_sid || !group_sid) {
 | 
|---|
| 322 |                 DEBUG(1, ("Sam account is missing sids!\n"));
 | 
|---|
| 323 |                 return NT_STATUS_UNSUCCESSFUL;
 | 
|---|
| 324 |         }
 | 
|---|
| 325 | 
 | 
|---|
| 326 |         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
 | 
|---|
| 327 |         if (!info3) {
 | 
|---|
| 328 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 329 |         }
 | 
|---|
| 330 | 
 | 
|---|
| 331 |         ZERO_STRUCT(domain_sid);
 | 
|---|
| 332 | 
 | 
|---|
| 333 |         /* check if this is a "Unix Users" domain user,
 | 
|---|
| 334 |          * we need to handle it in a special way if that's the case */
 | 
|---|
| 335 |         if (sid_check_is_in_unix_users(user_sid)) {
 | 
|---|
| 336 |                 /* in info3 you can only set rids for the user and the
 | 
|---|
| 337 |                  * primary group, and the domain sid must be that of
 | 
|---|
| 338 |                  * the sam domain.
 | 
|---|
| 339 |                  *
 | 
|---|
| 340 |                  * Store a completely bogus value here.
 | 
|---|
| 341 |                  * The real SID is stored in the extra sids.
 | 
|---|
| 342 |                  * Other code will know to look there if (-1) is found
 | 
|---|
| 343 |                  */
 | 
|---|
| 344 |                 info3->base.rid = (uint32_t)(-1);
 | 
|---|
| 345 |                 sid_copy(&extra->user_sid, user_sid);
 | 
|---|
| 346 | 
 | 
|---|
| 347 |                 DEBUG(10, ("Unix User found in struct samu. Rid marked as "
 | 
|---|
| 348 |                            "special and sid (%s) saved as extra sid\n",
 | 
|---|
| 349 |                            sid_string_dbg(user_sid)));
 | 
|---|
| 350 |         } else {
 | 
|---|
| 351 |                 sid_copy(&domain_sid, user_sid);
 | 
|---|
| 352 |                 sid_split_rid(&domain_sid, &info3->base.rid);
 | 
|---|
| 353 |         }
 | 
|---|
| 354 | 
 | 
|---|
| 355 |         if (is_null_sid(&domain_sid)) {
 | 
|---|
| 356 |                 sid_copy(&domain_sid, get_global_sam_sid());
 | 
|---|
| 357 |         }
 | 
|---|
| 358 | 
 | 
|---|
| 359 |         /* check if this is a "Unix Groups" domain group,
 | 
|---|
| 360 |          * if so we need special handling */
 | 
|---|
| 361 |         if (sid_check_is_in_unix_groups(group_sid)) {
 | 
|---|
| 362 |                 /* in info3 you can only set rids for the user and the
 | 
|---|
| 363 |                  * primary group, and the domain sid must be that of
 | 
|---|
| 364 |                  * the sam domain.
 | 
|---|
| 365 |                  *
 | 
|---|
| 366 |                  * Store a completely bogus value here.
 | 
|---|
| 367 |                  * The real SID is stored in the extra sids.
 | 
|---|
| 368 |                  * Other code will know to look there if (-1) is found
 | 
|---|
| 369 |                  */
 | 
|---|
| 370 |                 info3->base.primary_gid = (uint32_t)(-1);
 | 
|---|
| 371 |                 sid_copy(&extra->pgid_sid, group_sid);
 | 
|---|
| 372 | 
 | 
|---|
| 373 |                 DEBUG(10, ("Unix Group found in struct samu. Rid marked as "
 | 
|---|
| 374 |                            "special and sid (%s) saved as extra sid\n",
 | 
|---|
| 375 |                            sid_string_dbg(group_sid)));
 | 
|---|
| 376 | 
 | 
|---|
| 377 |         } else {
 | 
|---|
| 378 |                 ok = sid_peek_check_rid(&domain_sid, group_sid,
 | 
|---|
| 379 |                                         &info3->base.primary_gid);
 | 
|---|
| 380 |                 if (!ok) {
 | 
|---|
| 381 |                         DEBUG(1, ("The primary group domain sid(%s) does not "
 | 
|---|
| 382 |                                   "match the domain sid(%s) for %s(%s)\n",
 | 
|---|
| 383 |                                   sid_string_dbg(group_sid),
 | 
|---|
| 384 |                                   sid_string_dbg(&domain_sid),
 | 
|---|
| 385 |                                   pdb_get_username(samu),
 | 
|---|
| 386 |                                   sid_string_dbg(user_sid)));
 | 
|---|
| 387 |                         TALLOC_FREE(info3);
 | 
|---|
| 388 |                         return NT_STATUS_UNSUCCESSFUL;
 | 
|---|
| 389 |                 }
 | 
|---|
| 390 |         }
 | 
|---|
| 391 | 
 | 
|---|
| 392 |         unix_to_nt_time(&info3->base.last_logon, pdb_get_logon_time(samu));
 | 
|---|
| 393 |         unix_to_nt_time(&info3->base.last_logoff, get_time_t_max());
 | 
|---|
| 394 |         unix_to_nt_time(&info3->base.acct_expiry, get_time_t_max());
 | 
|---|
| 395 |         unix_to_nt_time(&info3->base.last_password_change,
 | 
|---|
| 396 |                         pdb_get_pass_last_set_time(samu));
 | 
|---|
| 397 |         unix_to_nt_time(&info3->base.allow_password_change,
 | 
|---|
| 398 |                         pdb_get_pass_can_change_time(samu));
 | 
|---|
| 399 |         unix_to_nt_time(&info3->base.force_password_change,
 | 
|---|
| 400 |                         pdb_get_pass_must_change_time(samu));
 | 
|---|
| 401 | 
 | 
|---|
| 402 |         tmp = pdb_get_username(samu);
 | 
|---|
| 403 |         if (tmp) {
 | 
|---|
| 404 |                 info3->base.account_name.string = talloc_strdup(info3, tmp);
 | 
|---|
| 405 |                 RET_NOMEM(info3->base.account_name.string);
 | 
|---|
| 406 |         }
 | 
|---|
| 407 |         tmp = pdb_get_fullname(samu);
 | 
|---|
| 408 |         if (tmp) {
 | 
|---|
| 409 |                 info3->base.full_name.string = talloc_strdup(info3, tmp);
 | 
|---|
| 410 |                 RET_NOMEM(info3->base.full_name.string);
 | 
|---|
| 411 |         }
 | 
|---|
| 412 |         tmp = pdb_get_logon_script(samu);
 | 
|---|
| 413 |         if (tmp) {
 | 
|---|
| 414 |                 info3->base.logon_script.string = talloc_strdup(info3, tmp);
 | 
|---|
| 415 |                 RET_NOMEM(info3->base.logon_script.string);
 | 
|---|
| 416 |         }
 | 
|---|
| 417 |         tmp = pdb_get_profile_path(samu);
 | 
|---|
| 418 |         if (tmp) {
 | 
|---|
| 419 |                 info3->base.profile_path.string = talloc_strdup(info3, tmp);
 | 
|---|
| 420 |                 RET_NOMEM(info3->base.profile_path.string);
 | 
|---|
| 421 |         }
 | 
|---|
| 422 |         tmp = pdb_get_homedir(samu);
 | 
|---|
| 423 |         if (tmp) {
 | 
|---|
| 424 |                 info3->base.home_directory.string = talloc_strdup(info3, tmp);
 | 
|---|
| 425 |                 RET_NOMEM(info3->base.home_directory.string);
 | 
|---|
| 426 |         }
 | 
|---|
| 427 |         tmp = pdb_get_dir_drive(samu);
 | 
|---|
| 428 |         if (tmp) {
 | 
|---|
| 429 |                 info3->base.home_drive.string = talloc_strdup(info3, tmp);
 | 
|---|
| 430 |                 RET_NOMEM(info3->base.home_drive.string);
 | 
|---|
| 431 |         }
 | 
|---|
| 432 | 
 | 
|---|
| 433 |         info3->base.logon_count = pdb_get_logon_count(samu);
 | 
|---|
| 434 |         info3->base.bad_password_count = pdb_get_bad_password_count(samu);
 | 
|---|
| 435 | 
 | 
|---|
| 436 |         info3->base.domain.string = talloc_strdup(info3,
 | 
|---|
| 437 |                                                   pdb_get_domain(samu));
 | 
|---|
| 438 |         RET_NOMEM(info3->base.domain.string);
 | 
|---|
| 439 | 
 | 
|---|
| 440 |         info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
 | 
|---|
| 441 |         RET_NOMEM(info3->base.domain_sid);
 | 
|---|
| 442 | 
 | 
|---|
| 443 |         status = pdb_enum_group_memberships(mem_ctx, samu,
 | 
|---|
| 444 |                                             &group_sids, &gids,
 | 
|---|
| 445 |                                             &num_group_sids);
 | 
|---|
| 446 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 447 |                 DEBUG(1, ("Failed to get groups from sam account.\n"));
 | 
|---|
| 448 |                 TALLOC_FREE(info3);
 | 
|---|
| 449 |                 return status;
 | 
|---|
| 450 |         }
 | 
|---|
| 451 | 
 | 
|---|
| 452 |         if (num_group_sids) {
 | 
|---|
| 453 |                 status = group_sids_to_info3(info3, group_sids, num_group_sids);
 | 
|---|
| 454 |                 if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 455 |                         TALLOC_FREE(info3);
 | 
|---|
| 456 |                         return status;
 | 
|---|
| 457 |                 }
 | 
|---|
| 458 |         }
 | 
|---|
| 459 | 
 | 
|---|
| 460 |         /* We don't need sids and gids after the conversion */
 | 
|---|
| 461 |         TALLOC_FREE(group_sids);
 | 
|---|
| 462 |         TALLOC_FREE(gids);
 | 
|---|
| 463 |         num_group_sids = 0;
 | 
|---|
| 464 | 
 | 
|---|
| 465 |         /* FIXME: should we add other flags ? */
 | 
|---|
| 466 |         info3->base.user_flags = NETLOGON_EXTRA_SIDS;
 | 
|---|
| 467 | 
 | 
|---|
| 468 |         if (login_server) {
 | 
|---|
| 469 |                 info3->base.logon_server.string = talloc_strdup(info3, login_server);
 | 
|---|
| 470 |                 RET_NOMEM(info3->base.logon_server.string);
 | 
|---|
| 471 |         }
 | 
|---|
| 472 | 
 | 
|---|
| 473 |         info3->base.acct_flags = pdb_get_acct_ctrl(samu);
 | 
|---|
| 474 | 
 | 
|---|
| 475 |         *_info3 = info3;
 | 
|---|
| 476 |         return NT_STATUS_OK;
 | 
|---|
| 477 | }
 | 
|---|
| 478 | 
 | 
|---|
| 479 | #undef RET_NOMEM
 | 
|---|
| 480 | 
 | 
|---|
| 481 | #define RET_NOMEM(ptr) do { \
 | 
|---|
| 482 |         if (!ptr) { \
 | 
|---|
| 483 |                 TALLOC_FREE(info3); \
 | 
|---|
| 484 |                 return NULL; \
 | 
|---|
| 485 |         } } while(0)
 | 
|---|
| 486 | 
 | 
|---|
| 487 | struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
 | 
|---|
| 488 |                                          struct netr_SamInfo3 *orig)
 | 
|---|
| 489 | {
 | 
|---|
| 490 |         struct netr_SamInfo3 *info3;
 | 
|---|
| 491 |         unsigned int i;
 | 
|---|
| 492 |         NTSTATUS status;
 | 
|---|
| 493 | 
 | 
|---|
| 494 |         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
 | 
|---|
| 495 |         if (!info3) return NULL;
 | 
|---|
| 496 | 
 | 
|---|
| 497 |         status = copy_netr_SamBaseInfo(info3, &orig->base, &info3->base);
 | 
|---|
| 498 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 499 |                 TALLOC_FREE(info3);
 | 
|---|
| 500 |                 return NULL;
 | 
|---|
| 501 |         }
 | 
|---|
| 502 | 
 | 
|---|
| 503 |         if (orig->sidcount) {
 | 
|---|
| 504 |                 info3->sidcount = orig->sidcount;
 | 
|---|
| 505 |                 info3->sids = talloc_array(info3, struct netr_SidAttr,
 | 
|---|
| 506 |                                            orig->sidcount);
 | 
|---|
| 507 |                 RET_NOMEM(info3->sids);
 | 
|---|
| 508 |                 for (i = 0; i < orig->sidcount; i++) {
 | 
|---|
| 509 |                         info3->sids[i].sid = dom_sid_dup(info3->sids,
 | 
|---|
| 510 |                                                             orig->sids[i].sid);
 | 
|---|
| 511 |                         RET_NOMEM(info3->sids[i].sid);
 | 
|---|
| 512 |                         info3->sids[i].attributes =
 | 
|---|
| 513 |                                 orig->sids[i].attributes;
 | 
|---|
| 514 |                 }
 | 
|---|
| 515 |         }
 | 
|---|
| 516 | 
 | 
|---|
| 517 |         return info3;
 | 
|---|
| 518 | }
 | 
|---|
| 519 | 
 | 
|---|
| 520 | static NTSTATUS wbcsids_to_samr_RidWithAttributeArray(
 | 
|---|
| 521 |                                 TALLOC_CTX *mem_ctx,
 | 
|---|
| 522 |                                 struct samr_RidWithAttributeArray *groups,
 | 
|---|
| 523 |                                 const struct dom_sid *domain_sid,
 | 
|---|
| 524 |                                 const struct wbcSidWithAttr *sids,
 | 
|---|
| 525 |                                 size_t num_sids)
 | 
|---|
| 526 | {
 | 
|---|
| 527 |         unsigned int i, j = 0;
 | 
|---|
| 528 |         bool ok;
 | 
|---|
| 529 | 
 | 
|---|
| 530 |         groups->rids = talloc_array(mem_ctx,
 | 
|---|
| 531 |                                     struct samr_RidWithAttribute, num_sids);
 | 
|---|
| 532 |         if (!groups->rids) {
 | 
|---|
| 533 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 534 |         }
 | 
|---|
| 535 | 
 | 
|---|
| 536 |         /* a wbcDomainSid is the same as a dom_sid */
 | 
|---|
| 537 |         for (i = 0; i < num_sids; i++) {
 | 
|---|
| 538 |                 ok = sid_peek_check_rid(domain_sid,
 | 
|---|
| 539 |                                         (const struct dom_sid *)&sids[i].sid,
 | 
|---|
| 540 |                                         &groups->rids[j].rid);
 | 
|---|
| 541 |                 if (!ok) continue;
 | 
|---|
| 542 | 
 | 
|---|
| 543 |                 groups->rids[j].attributes = SE_GROUP_MANDATORY |
 | 
|---|
| 544 |                                              SE_GROUP_ENABLED_BY_DEFAULT |
 | 
|---|
| 545 |                                              SE_GROUP_ENABLED;
 | 
|---|
| 546 |                 j++;
 | 
|---|
| 547 |         }
 | 
|---|
| 548 | 
 | 
|---|
| 549 |         groups->count = j;
 | 
|---|
| 550 |         return NT_STATUS_OK;
 | 
|---|
| 551 | }
 | 
|---|
| 552 | 
 | 
|---|
| 553 | static NTSTATUS wbcsids_to_netr_SidAttrArray(
 | 
|---|
| 554 |                                 const struct dom_sid *domain_sid,
 | 
|---|
| 555 |                                 const struct wbcSidWithAttr *sids,
 | 
|---|
| 556 |                                 size_t num_sids,
 | 
|---|
| 557 |                                 TALLOC_CTX *mem_ctx,
 | 
|---|
| 558 |                                 struct netr_SidAttr **_info3_sids,
 | 
|---|
| 559 |                                 uint32_t *info3_num_sids)
 | 
|---|
| 560 | {
 | 
|---|
| 561 |         unsigned int i, j = 0;
 | 
|---|
| 562 |         struct netr_SidAttr *info3_sids;
 | 
|---|
| 563 | 
 | 
|---|
| 564 |         info3_sids = talloc_array(mem_ctx, struct netr_SidAttr, num_sids);
 | 
|---|
| 565 |         if (info3_sids == NULL) {
 | 
|---|
| 566 |                 return NT_STATUS_NO_MEMORY;
 | 
|---|
| 567 |         }
 | 
|---|
| 568 | 
 | 
|---|
| 569 |         /* a wbcDomainSid is the same as a dom_sid */
 | 
|---|
| 570 |         for (i = 0; i < num_sids; i++) {
 | 
|---|
| 571 |                 const struct dom_sid *sid;
 | 
|---|
| 572 | 
 | 
|---|
| 573 |                 sid = (const struct dom_sid *)&sids[i].sid;
 | 
|---|
| 574 | 
 | 
|---|
| 575 |                 if (dom_sid_in_domain(domain_sid, sid)) {
 | 
|---|
| 576 |                         continue;
 | 
|---|
| 577 |                 }
 | 
|---|
| 578 | 
 | 
|---|
| 579 |                 info3_sids[j].sid = dom_sid_dup(info3_sids, sid);
 | 
|---|
| 580 |                 if (info3_sids[j].sid == NULL) {
 | 
|---|
| 581 |                         talloc_free(info3_sids);
 | 
|---|
| 582 |                         return NT_STATUS_NO_MEMORY;
 | 
|---|
| 583 |                 }
 | 
|---|
| 584 |                 info3_sids[j].attributes = SE_GROUP_MANDATORY |
 | 
|---|
| 585 |                                            SE_GROUP_ENABLED_BY_DEFAULT |
 | 
|---|
| 586 |                                            SE_GROUP_ENABLED;
 | 
|---|
| 587 |                 j++;
 | 
|---|
| 588 |         }
 | 
|---|
| 589 | 
 | 
|---|
| 590 |         *info3_num_sids = j;
 | 
|---|
| 591 |         *_info3_sids = info3_sids;
 | 
|---|
| 592 |         return NT_STATUS_OK;
 | 
|---|
| 593 | }
 | 
|---|
| 594 | 
 | 
|---|
| 595 | struct netr_SamInfo3 *wbcAuthUserInfo_to_netr_SamInfo3(TALLOC_CTX *mem_ctx,
 | 
|---|
| 596 |                                         const struct wbcAuthUserInfo *info)
 | 
|---|
| 597 | {
 | 
|---|
| 598 |         struct netr_SamInfo3 *info3;
 | 
|---|
| 599 |         struct dom_sid user_sid;
 | 
|---|
| 600 |         struct dom_sid group_sid;
 | 
|---|
| 601 |         struct dom_sid domain_sid;
 | 
|---|
| 602 |         NTSTATUS status;
 | 
|---|
| 603 |         bool ok;
 | 
|---|
| 604 | 
 | 
|---|
| 605 |         memcpy(&user_sid, &info->sids[0].sid, sizeof(user_sid));
 | 
|---|
| 606 |         memcpy(&group_sid, &info->sids[1].sid, sizeof(group_sid));
 | 
|---|
| 607 | 
 | 
|---|
| 608 |         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
 | 
|---|
| 609 |         if (!info3) return NULL;
 | 
|---|
| 610 | 
 | 
|---|
| 611 |         unix_to_nt_time(&info3->base.last_logon, info->logon_time);
 | 
|---|
| 612 |         unix_to_nt_time(&info3->base.last_logoff, info->logoff_time);
 | 
|---|
| 613 |         unix_to_nt_time(&info3->base.acct_expiry, info->kickoff_time);
 | 
|---|
| 614 |         unix_to_nt_time(&info3->base.last_password_change, info->pass_last_set_time);
 | 
|---|
| 615 |         unix_to_nt_time(&info3->base.allow_password_change,
 | 
|---|
| 616 |                         info->pass_can_change_time);
 | 
|---|
| 617 |         unix_to_nt_time(&info3->base.force_password_change,
 | 
|---|
| 618 |                         info->pass_must_change_time);
 | 
|---|
| 619 | 
 | 
|---|
| 620 |         if (info->account_name) {
 | 
|---|
| 621 |                 info3->base.account_name.string =
 | 
|---|
| 622 |                                 talloc_strdup(info3, info->account_name);
 | 
|---|
| 623 |                 RET_NOMEM(info3->base.account_name.string);
 | 
|---|
| 624 |         }
 | 
|---|
| 625 |         if (info->full_name) {
 | 
|---|
| 626 |                 info3->base.full_name.string =
 | 
|---|
| 627 |                                 talloc_strdup(info3, info->full_name);
 | 
|---|
| 628 |                 RET_NOMEM(info3->base.full_name.string);
 | 
|---|
| 629 |         }
 | 
|---|
| 630 |         if (info->logon_script) {
 | 
|---|
| 631 |                 info3->base.logon_script.string =
 | 
|---|
| 632 |                                 talloc_strdup(info3, info->logon_script);
 | 
|---|
| 633 |                 RET_NOMEM(info3->base.logon_script.string);
 | 
|---|
| 634 |         }
 | 
|---|
| 635 |         if (info->profile_path) {
 | 
|---|
| 636 |                 info3->base.profile_path.string =
 | 
|---|
| 637 |                                 talloc_strdup(info3, info->profile_path);
 | 
|---|
| 638 |                 RET_NOMEM(info3->base.profile_path.string);
 | 
|---|
| 639 |         }
 | 
|---|
| 640 |         if (info->home_directory) {
 | 
|---|
| 641 |                 info3->base.home_directory.string =
 | 
|---|
| 642 |                                 talloc_strdup(info3, info->home_directory);
 | 
|---|
| 643 |                 RET_NOMEM(info3->base.home_directory.string);
 | 
|---|
| 644 |         }
 | 
|---|
| 645 |         if (info->home_drive) {
 | 
|---|
| 646 |                 info3->base.home_drive.string =
 | 
|---|
| 647 |                                 talloc_strdup(info3, info->home_drive);
 | 
|---|
| 648 |                 RET_NOMEM(info3->base.home_drive.string);
 | 
|---|
| 649 |         }
 | 
|---|
| 650 | 
 | 
|---|
| 651 |         info3->base.logon_count = info->logon_count;
 | 
|---|
| 652 |         info3->base.bad_password_count = info->bad_password_count;
 | 
|---|
| 653 | 
 | 
|---|
| 654 |         sid_copy(&domain_sid, &user_sid);
 | 
|---|
| 655 |         sid_split_rid(&domain_sid, &info3->base.rid);
 | 
|---|
| 656 | 
 | 
|---|
| 657 |         ok = sid_peek_check_rid(&domain_sid, &group_sid,
 | 
|---|
| 658 |                                 &info3->base.primary_gid);
 | 
|---|
| 659 |         if (!ok) {
 | 
|---|
| 660 |                 DEBUG(1, ("The primary group sid domain does not"
 | 
|---|
| 661 |                           "match user sid domain for user: %s\n",
 | 
|---|
| 662 |                           info->account_name));
 | 
|---|
| 663 |                 TALLOC_FREE(info3);
 | 
|---|
| 664 |                 return NULL;
 | 
|---|
| 665 |         }
 | 
|---|
| 666 | 
 | 
|---|
| 667 |         status = wbcsids_to_samr_RidWithAttributeArray(info3,
 | 
|---|
| 668 |                                                        &info3->base.groups,
 | 
|---|
| 669 |                                                        &domain_sid,
 | 
|---|
| 670 |                                                        &info->sids[1],
 | 
|---|
| 671 |                                                        info->num_sids - 1);
 | 
|---|
| 672 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 673 |                 TALLOC_FREE(info3);
 | 
|---|
| 674 |                 return NULL;
 | 
|---|
| 675 |         }
 | 
|---|
| 676 | 
 | 
|---|
| 677 |         status = wbcsids_to_netr_SidAttrArray(&domain_sid,
 | 
|---|
| 678 |                                               &info->sids[1],
 | 
|---|
| 679 |                                               info->num_sids - 1,
 | 
|---|
| 680 |                                               info3,
 | 
|---|
| 681 |                                               &info3->sids,
 | 
|---|
| 682 |                                               &info3->sidcount);
 | 
|---|
| 683 |         if (!NT_STATUS_IS_OK(status)) {
 | 
|---|
| 684 |                 TALLOC_FREE(info3);
 | 
|---|
| 685 |                 return NULL;
 | 
|---|
| 686 |         }
 | 
|---|
| 687 | 
 | 
|---|
| 688 |         info3->base.user_flags = info->user_flags;
 | 
|---|
| 689 |         memcpy(info3->base.key.key, info->user_session_key, 16);
 | 
|---|
| 690 | 
 | 
|---|
| 691 |         if (info->logon_server) {
 | 
|---|
| 692 |                 info3->base.logon_server.string =
 | 
|---|
| 693 |                                 talloc_strdup(info3, info->logon_server);
 | 
|---|
| 694 |                 RET_NOMEM(info3->base.logon_server.string);
 | 
|---|
| 695 |         }
 | 
|---|
| 696 |         if (info->domain_name) {
 | 
|---|
| 697 |                 info3->base.domain.string =
 | 
|---|
| 698 |                                 talloc_strdup(info3, info->domain_name);
 | 
|---|
| 699 |                 RET_NOMEM(info3->base.domain.string);
 | 
|---|
| 700 |         }
 | 
|---|
| 701 | 
 | 
|---|
| 702 |         info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
 | 
|---|
| 703 |         RET_NOMEM(info3->base.domain_sid);
 | 
|---|
| 704 | 
 | 
|---|
| 705 |         memcpy(info3->base.LMSessKey.key, info->lm_session_key, 8);
 | 
|---|
| 706 |         info3->base.acct_flags = info->acct_flags;
 | 
|---|
| 707 | 
 | 
|---|
| 708 |         return info3;
 | 
|---|
| 709 | }
 | 
|---|