This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[nivanova/samba-autobuild/.git] / source3 / passdb / pdb_nisplus.c
1
2 /*
3  * NIS+ Passdb Backend
4  * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
5  * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se> 
6  * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
7  * Copyright (C) Toomas Soome <tsoome@ut.ee> 2001
8  * Copyright (C) Jelmer Vernooij 2002
9  * 
10  * This program is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  * 
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  * 
20  * You should have received a copy of the GNU General Public License along with
21  * this program; if not, write to the Free Software Foundation, Inc., 675
22  * Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "includes.h"
26
27 #ifdef WITH_NISPLUS_SAM
28
29 #ifdef BROKEN_NISPLUS_INCLUDE_FILES
30
31 /*
32  * The following lines are needed due to buggy include files
33  * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
34  * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
35  * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
36  * an enum in /usr/include/rpcsvc/nis.h.
37  */
38
39
40 #if defined(GROUP)
41 #undef GROUP
42 #endif
43
44 #if defined(GROUP_OBJ)
45 #undef GROUP_OBJ
46 #endif
47
48 #endif
49
50 #include <rpcsvc/nis.h>
51
52 /***************************************************************
53
54  the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
55
56                 name=S,nogw=r 
57                 uid=S,nogw=r 
58                 user_rid=S,nogw=r
59                 smb_grpid=,nw+r
60                 group_rid=,nw+r
61                 acb=,nw+r
62
63                 lmpwd=C,nw=,g=r,o=rm 
64                 ntpwd=C,nw=,g=r,o=rm 
65
66                 logon_t=,nw+r 
67                 logoff_t=,nw+r 
68                 kick_t=,nw+r 
69                 pwdlset_t=,nw+r 
70                 pwdlchg_t=,nw+r 
71                 pwdmchg_t=,nw+r 
72                                 
73                 full_name=,nw+r 
74                 home_dir=,nw+r 
75                 dir_drive=,nw+r 
76                 logon_script=,nw+r 
77                 profile_path=,nw+r 
78                 acct_desc=,nw+r 
79                 workstations=,nw+r 
80                                    
81                 hours=,nw+r 
82
83 ****************************************************************/
84
85 #define NPF_NAME          0
86 #define NPF_UID           1
87 #define NPF_USER_RID      2
88 #define NPF_SMB_GRPID     3
89 #define NPF_GROUP_RID     4
90 #define NPF_ACB           5
91 #define NPF_LMPWD         6
92 #define NPF_NTPWD         7
93 #define NPF_LOGON_T       8
94 #define NPF_LOGOFF_T      9
95 #define NPF_KICK_T        10
96 #define NPF_PWDLSET_T     11
97 #define NPF_PWDCCHG_T     12
98 #define NPF_PWDMCHG_T     13
99 #define NPF_FULL_NAME     14
100 #define NPF_HOME_DIR      15
101 #define NPF_DIR_DRIVE     16
102 #define NPF_LOGON_SCRIPT  17
103 #define NPF_PROFILE_PATH  18
104 #define NPF_ACCT_DESC     19
105 #define NPF_WORKSTATIONS  20
106 #define NPF_HOURS         21
107
108 struct nisplus_private_info {
109         nis_result *result;
110         int enum_entry;
111         char *location;
112 };
113
114 static char *make_nisname_from_user_rid (uint32 rid, char *pfile);
115 static char *make_nisname_from_name (const char *user_name, char *pfile);
116 static void get_single_attribute (const nis_object * new_obj, int col,
117                                   char *val, int len);;
118 static BOOL make_sam_from_nisp_object (SAM_ACCOUNT * pw_buf,
119                                        const nis_object * obj);
120 static BOOL make_sam_from_nisresult (SAM_ACCOUNT * pw_buf,
121                                      const nis_result * result);;
122 static void set_single_attribute (nis_object * new_obj, int col,
123                                   const char *val, int len, int flags);
124 static BOOL init_nisp_from_sam (nis_object * obj, const SAM_ACCOUNT * sampass,
125                                 nis_object * old);
126 static nis_result *nisp_get_nis_list (const char *nisname,
127                                       unsigned int flags);
128
129 /***************************************************************
130  Start enumeration of the passwd list.
131 ****************************************************************/
132
133 static NTSTATUS nisplussam_setsampwent (struct pdb_methods *methods, BOOL update)
134 {
135         struct nisplus_private_info *private =
136                 (struct nisplus_private_info *) methods->private_data;
137
138         char *sp;
139         pstring pfiletmp;
140
141         if ((sp = strrchr (private->location, '/')))
142                 safe_strcpy (pfiletmp, sp + 1, sizeof (pfiletmp) - 1);
143         else
144                 safe_strcpy (pfiletmp, p, sizeof (pfiletmp) - 1);
145         safe_strcat (pfiletmp, ".org_dir",
146                      sizeof (pfiletmp) - strlen (pfiletmp) - 1);
147
148         pdb_endsampwent ();     /* just in case */
149         global_nisp_ent->result = nisp_get_nis_list (pfiletmp, 0);
150         global_nisp_ent->enum_entry = 0;
151         if (global_nisp_ent->result != NULL) 
152                 return NT_STATUS_UNSUCCESSFUL;
153         else
154                 return NT_STATUS_OK;
155 }
156
157 /***************************************************************
158  End enumeration of the passwd list.
159 ****************************************************************/
160
161 static void nisplussam_endsampwent (struct pdb_methods *methods)
162 {
163         struct nisplus_private_info *global_nisp_ent =
164                 (struct nisplus_private_info *) methods->private_data;
165         if (global_nisp_ent->result)
166                 nis_freeresult (global_nisp_ent->result);
167         global_nisp_ent->result = NULL;
168         global_nisp_ent->enum_entry = 0;
169 }
170
171 /*****************************************************************
172  Get one SAM_ACCOUNT from the list (next in line)
173 *****************************************************************/
174
175 static NTSTATUS nisplussam_getsampwent (struct pdb_methods *methods,
176                                     SAM_ACCOUNT * user)
177 {
178         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
179         struct nisplus_private_info *global_nisp_ent =
180                 (struct nisplus_private_info *) methods->private_data;
181         int enum_entry = (int) (global_nisp_ent->enum_entry);
182         nis_result *result = global_nisp_ent->result;
183
184         if (user == NULL) {
185                 DEBUG (0, ("SAM_ACCOUNT is NULL.\n"));
186                 return nt_status;
187         }
188
189         if (result == NULL || enum_entry < 0 || enum_entry >= (NIS_RES_NUMOBJ (result) - 1)) {
190                 return nt_status;
191         }
192
193         if (!make_sam_from_nisp_object(user, &NIS_RES_OBJECT (result)[enum_entry])) {
194                 DEBUG (0, ("Bad SAM_ACCOUNT entry returned from NIS+!\n"));
195                 return nt_status;
196         }
197         (int) (global_nisp_ent->enum_entry)++;
198
199         return nt_status;
200 }
201
202 /******************************************************************
203  Lookup a name in the SAM database
204 ******************************************************************/
205
206 static NTSTATUS nisplussam_getsampwnam (struct pdb_methods *methods,
207                                     SAM_ACCOUNT * user, const char *sname)
208 {
209         /* Static buffers we will return. */
210         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
211         nis_result *result = NULL;
212         pstring nisname;
213         BOOL ret;
214         struct nisplus_private_info *private =
215                 (struct nisplus_private_info *) methods->private_data;
216
217         if (!private->location || !(*private->location)) {
218                 DEBUG (0, ("No SMB password file set\n"));
219                 return nt_status;
220         }
221         if (strrchr (private->location, '/'))
222                 private->location = strrchr (private->location, '/') + 1;
223
224         slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.org_dir",
225                   sname, private->location);
226         DEBUG (10, ("search by nisname: %s\n", nisname));
227
228         /* Search the table. */
229
230         if (!(result = nisp_get_nis_list (nisname, 0))) {
231                 return nt_status;
232         }
233
234         ret = make_sam_from_nisresult (user, result);
235         nis_freeresult (result);
236
237         if (ret) nt_status = NT_STATUS_OK;
238
239         return nt_status;
240 }
241
242 /***************************************************************************
243  Search by sid
244  **************************************************************************/
245
246 static NTSTATUS nisplussam_getsampwrid (struct pdb_methods *methods,
247                                     SAM_ACCOUNT * user, uint32 rid)
248 {
249         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
250         nis_result *result;
251         char *nisname;
252         BOOL ret;
253         char *sp;
254         pstring pfiletmp;
255         struct nisplus_private_info *private =
256                 (struct nisplus_private_info *) methods->private_data;
257
258         if (!private->location || !(*private->location)) {
259                 DEBUG (0, ("no SMB password file set\n"));
260                 return nt_status;
261         }
262
263         if ((sp = strrchr (private->location, '/')))
264                 safe_strcpy (pfiletmp, sp + 1, sizeof (pfiletmp) - 1);
265         else
266                 safe_strcpy (pfiletmp, private->location, sizeof (pfiletmp) - 1);
267         safe_strcat (pfiletmp, ".org_dir",
268                      sizeof (pfiletmp) - strlen (pfiletmp) - 1);
269
270         nisname = make_nisname_from_user_rid (rid, pfiletmp);
271
272         DEBUG (10, ("search by rid: %s\n", nisname));
273
274         /* Search the table. */
275
276         if (!(result = nisp_get_nis_list (nisname, 0))) {
277                 return nt_status;
278         }
279
280         ret = make_sam_from_nisresult (user, result);
281         nis_freeresult (result);
282
283         if (ret) nt_status = NT_STATUS_OK;
284
285         return nt_status;
286 }
287
288 static NTSTATUS nisplussam_getsampwsid (struct pdb_methods *methods,
289                                     SAM_ACCOUNT * user, const DOM_SID * sid)
290 {
291         uint32 rid;
292
293         if (!sid_peek_check_rid (get_global_sam_sid (), sid, &rid))
294                 return NT_STATUS_UNSUCCESSFUL;
295         return nisplussam_getsampwrid (methods, user, rid);
296 }
297
298
299
300 /***************************************************************************
301  Delete a SAM_ACCOUNT
302 ****************************************************************************/
303
304 static NTSTATUS nisplussam_delete_sam_account (struct pdb_methods *methods,
305                                                 SAM_ACCOUNT * user)
306 {
307         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
308         const char *sname;
309         pstring nisname;
310         nis_result *result, *delresult;
311         nis_object *obj;
312         struct nisplus_private_info *private =
313                 (struct nisplus_private_info *) methods->private_data;
314
315         if (!user) {
316                 DEBUG (0, ("no SAM_ACCOUNT specified!\n"));
317                 return nt_status;
318         }
319
320         sname = pdb_get_username (user);
321
322         if (!private->location || !(*private->location)) {
323                 DEBUG (0, ("no SMB password file set\n"));
324                 return nt_status;
325         }
326
327         if (strrchr (private->location, '/'))
328                 private->location = strrchr (private->location, '/') + 1;
329
330         slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.org_dir",
331                   sname, private->location);
332
333         /* Search the table. */
334
335         if (!(result = nisp_get_nis_list (nisname,
336                                           MASTER_ONLY | FOLLOW_LINKS |
337                                           FOLLOW_PATH | EXPAND_NAME |
338                                           HARD_LOOKUP))) {
339                 return nt_status;
340         }
341
342         if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ (result) <= 0) {
343                 /* User not found. */
344                 DEBUG (0, ("user not found in NIS+\n"));
345                 nis_freeresult (result);
346                 return nt_status;
347         }
348
349         obj = NIS_RES_OBJECT (result);
350         slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.%s", sname,
351                   obj->zo_name, obj->zo_domain);
352
353         DEBUG (10, ("removing name: %s\n", nisname));
354         delresult = nis_remove_entry (nisname, obj,
355                                       MASTER_ONLY | REM_MULTIPLE | ALL_RESULTS
356                                       | FOLLOW_PATH | EXPAND_NAME |
357                                       HARD_LOOKUP);
358
359         nis_freeresult (result);
360
361         if (delresult->status != NIS_SUCCESS) {
362                 DEBUG (0, ("NIS+ table update failed: %s %s\n",
363                            nisname, nis_sperrno (delresult->status)));
364                 nis_freeresult (delresult);
365                 return nt_status;
366         }
367         nis_freeresult (delresult);
368
369         return NT_STATUS_OK;
370 }
371
372 /***************************************************************************
373  Modifies an existing SAM_ACCOUNT
374 ****************************************************************************/
375
376 static NTSTATUS nisplussam_update_sam_account (struct pdb_methods *methods,
377                                            SAM_ACCOUNT * newpwd)
378 {
379         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
380         nis_result *result, *addresult;
381         nis_object *obj;
382         nis_object new_obj;
383         entry_col *ecol;
384         int ta_maxcol;
385         struct nisplus_private_info *private =
386                 (struct nisplus_private_info *) methods->private_data;
387         pstring nisname;
388
389         if (!private->location || !(*private->location)) {
390                 DEBUG (0, ("no SMB password file set\n"));
391                 return nt_status;
392         }
393         if (strrchr (private->location, '/'))
394                 private->location = strrchr (private->location, '/') + 1;
395
396         slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.org_dir",
397                   pdb_get_username (newpwd), private->location);
398
399         DEBUG (10, ("search by name: %s\n", nisname));
400
401         /* Search the table. */
402
403         if (!
404             (result =
405              nisp_get_nis_list (nisname,
406                                 MASTER_ONLY | FOLLOW_LINKS | FOLLOW_PATH |
407                                 EXPAND_NAME | HARD_LOOKUP))) {
408                 return ne_status;
409         }
410
411         if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ (result) <= 0) {
412                 /* User not found. */
413                 DEBUG (0, ("user not found in NIS+\n"));
414                 nis_freeresult (result);
415                 return nt_status;
416         }
417
418         obj = NIS_RES_OBJECT (result);
419         DEBUG (6, ("entry found in %s\n", obj->zo_domain));
420
421         /* we must create new stub object with EN_MODIFIED flag.
422            this is because obj from result is going to be freed and
423            we do not want to break it or cause memory leaks or corruption.
424          */
425
426         memmove ((char *) &new_obj, obj, sizeof (new_obj));
427         ta_maxcol = obj->TA_data.ta_maxcol;
428
429         if (!(ecol = (entry_col *) malloc (ta_maxcol * sizeof (entry_col)))) {
430                 DEBUG (0, ("memory allocation failure\n"));
431                 nis_freeresult (result);
432                 return nt_status;
433         }
434
435         memmove ((char *) ecol, obj->EN_data.en_cols.en_cols_val,
436                  ta_maxcol * sizeof (entry_col));
437         new_obj.EN_data.en_cols.en_cols_val = ecol;
438         new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
439
440         if (init_nisp_from_sam (&new_obj, newpwd, obj) == True) {
441                 slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.%s",
442                           pdb_get_username (newpwd), private->location, obj->zo_domain);
443
444                 DEBUG (10, ("NIS+ table update: %s\n", nisname));
445                 addresult =
446                         nis_modify_entry (nisname, &new_obj,
447                                           MOD_SAMEOBJ | FOLLOW_PATH |
448                                           EXPAND_NAME | HARD_LOOKUP);
449
450                 if (addresult->status != NIS_SUCCESS) {
451                         DEBUG (0, ("NIS+ table update failed: %s %s\n",
452                                    nisname, nis_sperrno (addresult->status)));
453                         nis_freeresult (addresult);
454                         nis_freeresult (result);
455                         free (ecol);
456                         return nt_status;
457                 }
458
459                 DEBUG (6, ("password changed\n"));
460                 nis_freeresult (addresult);
461         } else {
462                 DEBUG (6, ("nothing to change!\n"));
463         }
464
465         free (ecol);
466         nis_freeresult (result);
467
468         return NT_STATUS_OK;
469 }
470
471 /***************************************************************************
472  Adds an existing SAM_ACCOUNT
473 ****************************************************************************/
474
475 static NTSTATUS nisplussam_add_sam_account (struct pdb_methods *methods,
476                                         SAM_ACCOUNT * newpwd)
477 {
478         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
479         int local_user = 0;
480         char *pfile;
481         pstring pfiletmp;
482         char *nisname;
483         nis_result *result = NULL, *tblresult = NULL;
484         nis_object new_obj;
485         entry_col *ecol;
486         int ta_maxcol;
487
488         /*
489          * 1. find user domain.
490          *   a. try nis search in passwd.org_dir - if found use domain from result.
491          *   b. try getpwnam. this may be needed if user is defined
492          *      in /etc/passwd file (or elsewere) and not in passwd.org_dir.
493          *      if found, use host default domain.
494          *   c. exit with False - no such user.
495          *
496          * 2. add user
497          *   a. find smbpasswd table
498          *      search pfile in user domain if not found, try host default
499          *      domain. 
500          *   b. smbpasswd domain is found, fill data and add entry.
501          *
502          * pfile should contain ONLY table name, org_dir will be concated.
503          * so, at first we will clear path prefix from pfile, and
504          * then we will use pfiletmp as playground to put together full
505          * nisname string.
506          * such approach will make it possible to specify samba private dir
507          * AND still use NIS+ table. as all domain related data is normally
508          * stored in org_dir.DOMAIN, this should be ok do do.
509          */
510
511         pfile = private->location;
512         if (strrchr (pfile, '/'))
513                 pfile = strrchr (pfile, '/') + 1;
514
515         /*
516          * Check if user is already there.
517          */
518         safe_strcpy (pfiletmp, pfile, sizeof (pfiletmp) - 1);
519         safe_strcat (pfiletmp, ".org_dir",
520                      sizeof (pfiletmp) - strlen (pfiletmp) - 1);
521
522         if (pdb_get_username (newpwd) != NULL) {
523                 nisname = make_nisname_from_name (pdb_get_username (newpwd),
524                                                   pfiletmp);
525         } else {
526                 return nt_status;
527         }
528
529         if (!
530             (result =
531              nisp_get_nis_list (nisname,
532                                 MASTER_ONLY | FOLLOW_LINKS | FOLLOW_PATH |
533                                 EXPAND_NAME | HARD_LOOKUP))) {
534                 return nt_status;
535         }
536         if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND) {
537                 DEBUG (3, ("nis_list failure: %s: %s\n",
538                            nisname, nis_sperrno (result->status)));
539                 nis_freeresult (result);
540                 return nt_status;
541         }
542
543         if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ (result) > 0) {
544                 DEBUG (3, ("User already exists in NIS+ password db: %s\n",
545                            pfile));
546                 nis_freeresult (result);
547                 return nt_status;
548         }
549
550         nis_freeresult (result);        /* no such user, free results */
551
552         /*
553          * check for user in unix password database. we need this to get
554          * domain, where smbpasswd entry should be stored.
555          */
556
557         nisname = make_nisname_from_name (pdb_get_username (newpwd),
558                                           "passwd.org_dir");
559
560         result = nisp_get_nis_list (nisname,
561                                     MASTER_ONLY | FOLLOW_LINKS | FOLLOW_PATH |
562                                     EXPAND_NAME | HARD_LOOKUP);
563
564         if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ (result) <= 0) {
565                 struct passwd *passwd;
566
567                 DEBUG (3, ("nis_list failure: %s: %s\n",
568                            nisname, nis_sperrno (result->status)));
569                 nis_freeresult (result);
570
571                 if (!(passwd = getpwnam_alloc (pdb_get_username (newpwd)))) {
572                         /* no such user in system! */
573                         return nt_status;
574                 }
575                 passwd_free (&passwd);
576
577                 /* 
578                  * user is defined, but not in passwd.org_dir.
579                  */
580                 local_user = 1;
581         } else {
582                 safe_strcpy (pfiletmp, pfile, sizeof (pfiletmp) - 1);
583                 safe_strcat (pfiletmp, ".",
584                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
585                 safe_strcat (pfiletmp, NIS_RES_OBJECT (result)->zo_domain,
586                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
587                 nis_freeresult (result);        /* not needed any more */
588
589                 tblresult = nisp_get_nis_list (pfiletmp,
590                                                MASTER_ONLY | FOLLOW_LINKS |
591                                                FOLLOW_PATH | EXPAND_NAME |
592                                                HARD_LOOKUP);
593         }
594
595         if (local_user || tblresult->status != NIS_SUCCESS) {
596                 /*
597                  * no user domain or
598                  * smbpasswd table not found in user domain, fallback to
599                  * default domain.
600                  */
601                 if (!local_user)        /* free previous failed search result */
602                         nis_freeresult (tblresult);
603
604                 safe_strcpy (pfiletmp, pfile, sizeof (pfiletmp) - 1);
605                 safe_strcat (pfiletmp, ".org_dir",
606                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
607                 tblresult = nis_lookup (pfiletmp, MASTER_ONLY | FOLLOW_LINKS |
608                                         FOLLOW_PATH | EXPAND_NAME |
609                                         HARD_LOOKUP);
610                 if (tblresult->status != NIS_SUCCESS) {
611                         /* still nothing. bail out */
612                         nis_freeresult (tblresult);
613                         DEBUG (3, ("nis_lookup failure: %s\n",
614                                    nis_sperrno (tblresult->status)));
615                         return nt_status;
616                 }
617                 /* we need full name for nis_add_entry() */
618                 safe_strcpy (pfiletmp, pfile, sizeof (pfiletmp) - 1);
619                 safe_strcat (pfiletmp, ".",
620                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
621                 safe_strcat (pfiletmp, NIS_RES_OBJECT (tblresult)->zo_domain,
622                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
623         }
624
625         memset ((char *) &new_obj, 0, sizeof (new_obj));
626         /* fill entry headers */
627         /* we do not free these. */
628         new_obj.zo_name = NIS_RES_OBJECT (tblresult)->zo_name;
629         new_obj.zo_owner = NIS_RES_OBJECT (tblresult)->zo_owner;
630         new_obj.zo_group = NIS_RES_OBJECT (tblresult)->zo_group;
631         new_obj.zo_domain = NIS_RES_OBJECT (tblresult)->zo_domain;
632         /* uints */
633         new_obj.zo_access = NIS_RES_OBJECT (tblresult)->zo_access;
634         new_obj.zo_ttl = NIS_RES_OBJECT (tblresult)->zo_ttl;
635
636         new_obj.zo_data.zo_type = ENTRY_OBJ;
637         new_obj.EN_data.en_type = NIS_RES_OBJECT (tblresult)->TA_data.ta_type;
638
639         ta_maxcol = NIS_RES_OBJECT (tblresult)->TA_data.ta_maxcol;
640
641         if (!(ecol = (entry_col *) malloc (ta_maxcol * sizeof (entry_col)))) {
642                 DEBUG (0, ("memory allocation failure\n"));
643                 nis_freeresult (tblresult);
644                 return nt_status;
645         }
646
647         memset ((char *) ecol, 0, ta_maxcol * sizeof (entry_col));
648         new_obj.EN_data.en_cols.en_cols_val = ecol;
649         new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
650
651         init_nisp_from_sam (&new_obj, newpwd, NULL);
652
653         DEBUG (10, ("add NIS+ entry: %s\n", nisname));
654         result = nis_add_entry (pfiletmp, &new_obj, 0);
655
656         free (ecol);            /* free allocated entry space */
657
658         if (result->status != NIS_SUCCESS) {
659                 DEBUG (3, ("NIS+ table update failed: %s,%s\n",
660                            nisname, nis_sperrno (result->status)));
661                 nis_freeresult (tblresult);
662                 nis_freeresult (result);
663                 return nt_status;
664         }
665
666         nis_freeresult (tblresult);
667         nis_freeresult (result);
668
669         return NT_STATUS_OK;
670 }
671
672 /***************************************************************
673  make_nisname_from_user_rid
674  ****************************************************************/
675 static char *make_nisname_from_user_rid (uint32 rid, char *pfile)
676 {
677         static pstring nisname;
678
679         safe_strcpy (nisname, "[user_rid=", sizeof (nisname) - 1);
680         slprintf (nisname, sizeof (nisname) - 1, "%s%d", nisname, rid);
681         safe_strcat (nisname, "],", sizeof (nisname) - strlen (nisname) - 1);
682         safe_strcat (nisname, pfile, sizeof (nisname) - strlen (nisname) - 1);
683
684         return nisname;
685 }
686
687 /***************************************************************
688  make_nisname_from_name
689  ****************************************************************/
690 static char *make_nisname_from_name (const char *user_name, char *pfile)
691 {
692         static pstring nisname;
693
694         safe_strcpy (nisname, "[name=", sizeof (nisname) - 1);
695         safe_strcat (nisname, user_name,
696                      sizeof (nisname) - strlen (nisname) - 1);
697         safe_strcat (nisname, "],", sizeof (nisname) - strlen (nisname) - 1);
698         safe_strcat (nisname, pfile, sizeof (nisname) - strlen (nisname) - 1);
699
700         return nisname;
701 }
702
703 /*************************************************************************
704  gets a NIS+ attribute
705  *************************************************************************/
706 static void get_single_attribute (const nis_object * new_obj, int col,
707                                   char *val, int len)
708 {
709         int entry_len;
710
711         if (new_obj == NULL || val == NULL)
712                 return;
713
714         entry_len = ENTRY_LEN (new_obj, col);
715         if (len > entry_len) {
716                 len = entry_len;
717         }
718
719         safe_strcpy (val, ENTRY_VAL (new_obj, col), len - 1);
720 }
721
722 /************************************************************************
723  makes a struct sam_passwd from a NIS+ object.
724  ************************************************************************/
725 static BOOL make_sam_from_nisp_object (SAM_ACCOUNT * pw_buf,
726                                        const nis_object * obj)
727 {
728         char *ptr;
729         pstring full_name;      /* this must be translated to dos code page */
730         pstring acct_desc;      /* this must be translated to dos code page */
731         pstring home_dir;       /* set default value from smb.conf for user */
732         pstring home_drive;     /* set default value from smb.conf for user */
733         pstring logon_script;   /* set default value from smb.conf for user */
734         pstring profile_path;   /* set default value from smb.conf for user */
735         pstring hours;
736         int hours_len;
737         unsigned char smbpwd[16];
738         unsigned char smbntpwd[16];
739
740
741         /*
742          * time values. note: this code assumes 32bit time_t!
743          */
744
745         /* Don't change these timestamp settings without a good reason.  They are
746            important for NT member server compatibility. */
747
748         pdb_set_logon_time (pw_buf, (time_t) 0, PDB_DEFAULT);
749         ptr = (uchar *) ENTRY_VAL (obj, NPF_LOGON_T);
750         if (ptr && *ptr && (StrnCaseCmp (ptr, "LNT-", 4) == 0)) {
751                 int i;
752
753                 ptr += 4;
754                 for (i = 0; i < 8; i++) {
755                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
756                                 break;
757                 }
758                 if (i == 8) {
759                         pdb_set_logon_time (pw_buf,
760                                             (time_t) strtol (ptr, NULL, 16),
761                                             PDB_SET);
762                 }
763         }
764
765         pdb_set_logoff_time (pw_buf, get_time_t_max (), PDB_DEFAULT);
766         ptr = (uchar *) ENTRY_VAL (obj, NPF_LOGOFF_T);
767         if (ptr && *ptr && (StrnCaseCmp (ptr, "LOT-", 4) == 0)) {
768                 int i;
769
770                 ptr += 4;
771                 for (i = 0; i < 8; i++) {
772                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
773                                 break;
774                 }
775                 if (i == 8) {
776                         pdb_set_logoff_time (pw_buf,
777                                              (time_t) strtol (ptr, NULL, 16),
778                                              PDB_SET);
779                 }
780         }
781
782         pdb_set_kickoff_time (pw_buf, get_time_t_max (), PDB_DEFAULT);
783         ptr = (uchar *) ENTRY_VAL (obj, NPF_KICK_T);
784         if (ptr && *ptr && (StrnCaseCmp (ptr, "KOT-", 4) == 0)) {
785                 int i;
786
787                 ptr += 4;
788                 for (i = 0; i < 8; i++) {
789                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
790                                 break;
791                 }
792                 if (i == 8) {
793                         pdb_set_kickoff_time (pw_buf,
794                                               (time_t) strtol (ptr, NULL, 16),
795                                               PDB_SET);
796                 }
797         }
798
799         pdb_set_pass_last_set_time (pw_buf, (time_t) 0, PDB_DEFAULT);
800         ptr = (uchar *) ENTRY_VAL (obj, NPF_PWDLSET_T);
801         if (ptr && *ptr && (StrnCaseCmp (ptr, "LCT-", 4) == 0)) {
802                 int i;
803
804                 ptr += 4;
805                 for (i = 0; i < 8; i++) {
806                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
807                                 break;
808                 }
809                 if (i == 8) {
810                         pdb_set_pass_last_set_time (pw_buf,
811                                                     (time_t) strtol (ptr,
812                                                                      NULL,
813                                                                      16),
814                                                      PDB_SET);
815                 }
816         }
817
818         pdb_set_pass_can_change_time (pw_buf, (time_t) 0, PDB_DEFAULT);
819         ptr = (uchar *) ENTRY_VAL (obj, NPF_PWDCCHG_T);
820         if (ptr && *ptr && (StrnCaseCmp (ptr, "CCT-", 4) == 0)) {
821                 int i;
822
823                 ptr += 4;
824                 for (i = 0; i < 8; i++) {
825                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
826                                 break;
827                 }
828                 if (i == 8) {
829                         pdb_set_pass_can_change_time (pw_buf,
830                                                       (time_t) strtol (ptr,
831                                                                        NULL,
832                                                                        16),
833                                                       PDB_SET);
834                 }
835         }
836
837         pdb_set_pass_must_change_time (pw_buf, get_time_t_max (), PDB_DEFAULT); /* Password never expires. */
838         ptr = (uchar *) ENTRY_VAL (obj, NPF_PWDMCHG_T);
839         if (ptr && *ptr && (StrnCaseCmp (ptr, "MCT-", 4) == 0)) {
840                 int i;
841
842                 ptr += 4;
843                 for (i = 0; i < 8; i++) {
844                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
845                                 break;
846                 }
847                 if (i == 8) {
848                         pdb_set_pass_must_change_time (pw_buf,
849                                                        (time_t) strtol (ptr,
850                                                                         NULL,
851                                                                         16),
852                                                        PDB_SET);
853                 }
854         }
855
856         /* string values */
857         pdb_set_username (pw_buf, ENTRY_VAL (obj, NPF_NAME), PDB_SET);
858         pdb_set_domain (pw_buf, lp_workgroup (), PDB_DEFAULT);
859         /* pdb_set_nt_username() -- cant set it here... */
860
861         get_single_attribute (obj, NPF_FULL_NAME, full_name,
862                               sizeof (pstring));
863 #if 0
864         unix_to_dos (full_name, True);
865 #endif
866         pdb_set_fullname (pw_buf, full_name, PDB_SET);
867
868         pdb_set_acct_ctrl (pw_buf, pdb_decode_acct_ctrl (ENTRY_VAL (obj,
869                                                                     NPF_ACB), PDB_SET));
870
871         get_single_attribute (obj, NPF_ACCT_DESC, acct_desc,
872                               sizeof (pstring));
873 #if 0
874         unix_to_dos (acct_desc, True);
875 #endif
876         pdb_set_acct_desc (pw_buf, acct_desc, PDB_SET);
877
878         pdb_set_workstations (pw_buf, ENTRY_VAL (obj, NPF_WORKSTATIONS), PDB_SET);
879         pdb_set_munged_dial (pw_buf, NULL, PDB_DEFAULT);
880
881         pdb_set_uid (pw_buf, atoi (ENTRY_VAL (obj, NPF_UID)), PDB_SET);
882         pdb_set_gid (pw_buf, atoi (ENTRY_VAL (obj, NPF_SMB_GRPID)), PDB_SET);
883         pdb_set_user_sid_from_rid (pw_buf,
884                                    atoi (ENTRY_VAL (obj, NPF_USER_RID)), PDB_SET);
885         pdb_set_group_sid_from_rid (pw_buf,
886                                     atoi (ENTRY_VAL (obj, NPF_GROUP_RID)), PDB_SET);
887
888         /* values, must exist for user */
889         if (!(pdb_get_acct_ctrl (pw_buf) & ACB_WSTRUST)) {
890
891                 get_single_attribute (obj, NPF_HOME_DIR, home_dir,
892                                       sizeof (pstring));
893                 if (!(home_dir && *home_dir)) {
894                         pstrcpy (home_dir, lp_logon_home ());
895                         pdb_set_homedir (pw_buf, home_dir, PDB_DEFAULT);
896                 } else
897                         pdb_set_homedir (pw_buf, home_dir, PDB_SET);
898
899                 get_single_attribute (obj, NPF_DIR_DRIVE, home_drive,
900                                       sizeof (pstring));
901                 if (!(home_drive && *home_drive)) {
902                         pstrcpy (home_drive, lp_logon_drive ());
903                         pdb_set_dir_drive (pw_buf, home_drive, PDB_DEFAULT);
904                 } else
905                         pdb_set_dir_drive (pw_buf, home_drive, PDB_SET);
906
907                 get_single_attribute (obj, NPF_LOGON_SCRIPT, logon_script,
908                                       sizeof (pstring));
909                 if (!(logon_script && *logon_script)) {
910                         pstrcpy (logon_script, lp_logon_script ());
911                         pdb_set_logon_script (pw_buf, logon_script, PDB_DEFAULT);
912                 } else
913                         pdb_set_logon_script (pw_buf, logon_script, PDB_SET);
914
915                 get_single_attribute (obj, NPF_PROFILE_PATH, profile_path,
916                                       sizeof (pstring));
917                 if (!(profile_path && *profile_path)) {
918                         pstrcpy (profile_path, lp_logon_path ());
919                         pdb_set_profile_path (pw_buf, profile_path, PDB_DEFAULT);
920                 } else
921                         pdb_set_profile_path (pw_buf, profile_path, PDB_SET);
922
923         } else {
924                 /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
925                 pdb_set_group_sid_from_rid (pw_buf, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
926         }
927
928         /* Check the lanman password column. */
929         ptr = (char *) ENTRY_VAL (obj, NPF_LMPWD);
930         if (!pdb_set_lanman_passwd (pw_buf, NULL, PDB_DEFAULT))
931                 return False;
932
933         if (!strncasecmp (ptr, "NO PASSWORD", 11)) {
934                 pdb_set_acct_ctrl (pw_buf,
935                                    pdb_get_acct_ctrl (pw_buf) | ACB_PWNOTREQ, PDB_SET);
936         } else {
937                 if (strlen (ptr) != 32 || !pdb_gethexpwd (ptr, smbpwd)) {
938                         DEBUG (0, ("malformed LM pwd entry: %s.\n",
939                                    pdb_get_username (pw_buf)));
940                         return False;
941                 }
942                 if (!pdb_set_lanman_passwd (pw_buf, smbpwd, PDB_SET))
943                         return False;
944         }
945
946         /* Check the NT password column. */
947         ptr = ENTRY_VAL (obj, NPF_NTPWD);
948         if (!pdb_set_nt_passwd (pw_buf, NULL, PDB_DEFAULT))
949                 return False;
950
951         if (!(pdb_get_acct_ctrl (pw_buf) & ACB_PWNOTREQ) &&
952             strncasecmp (ptr, "NO PASSWORD", 11)) {
953                 if (strlen (ptr) != 32 || !pdb_gethexpwd (ptr, smbntpwd)) {
954                         DEBUG (0, ("malformed NT pwd entry:\
955  uid = %d.\n", pdb_get_uid (pw_buf)));
956                         return False;
957                 }
958                 if (!pdb_set_nt_passwd (pw_buf, smbntpwd, PDB_SET))
959                         return False;
960         }
961
962         pdb_set_unknown_3 (pw_buf, 0xffffff, PDB_DEFAULT);      /* don't know */
963         pdb_set_logon_divs (pw_buf, 168, PDB_DEFAULT);  /* hours per week */
964
965         if ((hours_len = ENTRY_LEN (obj, NPF_HOURS)) == 21) {
966                 memcpy (hours, ENTRY_VAL (obj, NPF_HOURS), hours_len);
967         } else {
968                 hours_len = 21; /* 21 times 8 bits = 168 */
969                 /* available at all hours */
970                 memset (hours, 0xff, hours_len);
971         }
972         pdb_set_hours_len (pw_buf, hours_len, PDB_SET);
973         pdb_set_hours (pw_buf, hours, PDB_SET);
974
975         pdb_set_unknown_5 (pw_buf, 0x00020000, PDB_DEFAULT);    /* don't know */
976         pdb_set_unknown_6 (pw_buf, 0x000004ec, PDB_DEFAULT);    /* don't know */
977
978         return True;
979 }
980
981 /************************************************************************
982  makes a struct sam_passwd from a NIS+ result.
983  ************************************************************************/
984 static BOOL make_sam_from_nisresult (SAM_ACCOUNT * pw_buf,
985                                      const nis_result * result)
986 {
987         if (pw_buf == NULL || result == NULL)
988                 return False;
989
990         if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND) {
991                 DEBUG (0, ("NIS+ lookup failure: %s\n",
992                            nis_sperrno (result->status)));
993                 return False;
994         }
995
996         /* User not found. */
997         if (NIS_RES_NUMOBJ (result) <= 0) {
998                 DEBUG (10, ("user not found in NIS+\n"));
999                 return False;
1000         }
1001
1002         if (NIS_RES_NUMOBJ (result) > 1) {
1003                 DEBUG (10,
1004                        ("WARNING: Multiple entries for user in NIS+ table!\n"));
1005         }
1006
1007         /* Grab the first hit. */
1008         return make_sam_from_nisp_object (pw_buf,
1009                                           &NIS_RES_OBJECT (result)[0]);
1010 }
1011
1012 /*************************************************************************
1013  sets a NIS+ attribute
1014  *************************************************************************/
1015 static void set_single_attribute (nis_object * new_obj, int col,
1016                                   const char *val, int len, int flags)
1017 {
1018         if (new_obj == NULL)
1019                 return;
1020
1021         ENTRY_VAL (new_obj, col) = val;
1022         ENTRY_LEN (new_obj, col) = len + 1;
1023
1024         if (flags != 0) {
1025                 new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
1026         }
1027 }
1028
1029 /***************************************************************
1030  copy or modify nis object. this object is used to add or update
1031  nisplus table entry.
1032  ****************************************************************/
1033 static BOOL init_nisp_from_sam (nis_object * obj, const SAM_ACCOUNT * sampass,
1034                                 nis_object * old)
1035 {
1036         /*
1037          * Fill nis_object for entry add or update.
1038          * if we are updateing, we have to find out differences and set
1039          * EN_MODIFIED flag. also set need_to_modify to trigger
1040          * nis_modify_entry() call in pdb_update_sam_account().
1041          *
1042          * TODO:
1043          *   get data from SAM
1044          *   if (modify) get data from nis_object, compare and store if
1045          *               different + set EN_MODIFIED and need_to_modify
1046          *   else
1047          *               store
1048          */
1049         BOOL need_to_modify = False;
1050         const char *name = pdb_get_username (sampass);  /* from SAM */
1051
1052         /* these must be static or allocate and free entry columns! */
1053         static fstring uid;     /* from SAM */
1054         static fstring user_rid;        /* from SAM */
1055         static fstring gid;     /* from SAM */
1056         static fstring group_rid;       /* from SAM */
1057         char *acb;              /* from SAM */
1058         static fstring smb_passwd;      /* from SAM */
1059         static fstring smb_nt_passwd;   /* from SAM */
1060         static fstring logon_t; /* from SAM */
1061         static fstring logoff_t;        /* from SAM */
1062         static fstring kickoff_t;       /* from SAM */
1063         static fstring pwdlset_t;       /* from SAM */
1064         static fstring pwdlchg_t;       /* from SAM */
1065         static fstring pwdmchg_t;       /* from SAM */
1066         static fstring full_name;       /* from SAM */
1067         static fstring acct_desc;       /* from SAM */
1068         static char empty[1];   /* just an empty string */
1069
1070         slprintf (uid, sizeof (uid) - 1, "%u", pdb_get_uid (sampass));
1071         slprintf (user_rid, sizeof (user_rid) - 1, "%u",
1072                   pdb_get_user_rid (sampass) ? pdb_get_user_rid (sampass) :
1073                   fallback_pdb_uid_to_user_rid (pdb_get_uid (sampass)));
1074         slprintf (gid, sizeof (gid) - 1, "%u", pdb_get_gid (sampass));
1075
1076         {
1077                 uint32 rid;
1078                 GROUP_MAP map;
1079
1080                 rid = pdb_get_group_rid (sampass);
1081
1082                 if (rid == 0) {
1083                         if (pdb_getgrgid(&map, pdb_get_gid (sampass),
1084                                          MAPPING_WITHOUT_PRIV)) {
1085                                 if (!sid_peek_check_rid
1086                                     (get_global_sam_sid (), &map.sid, &rid))
1087                                         return False;
1088                         } else
1089                                 rid = pdb_gid_to_group_rid (pdb_get_gid
1090                                                             (sampass));
1091                 }
1092
1093                 slprintf (group_rid, sizeof (group_rid) - 1, "%u", rid);
1094         }
1095
1096         acb = pdb_encode_acct_ctrl (pdb_get_acct_ctrl (sampass),
1097                                     NEW_PW_FORMAT_SPACE_PADDED_LEN);
1098         pdb_sethexpwd (smb_passwd, pdb_get_lanman_passwd (sampass),
1099                        pdb_get_acct_ctrl (sampass));
1100         pdb_sethexpwd (smb_nt_passwd, pdb_get_nt_passwd (sampass),
1101                        pdb_get_acct_ctrl (sampass));
1102         slprintf (logon_t, 13, "LNT-%08X",
1103                   (uint32) pdb_get_logon_time (sampass));
1104         slprintf (logoff_t, 13, "LOT-%08X",
1105                   (uint32) pdb_get_logoff_time (sampass));
1106         slprintf (kickoff_t, 13, "KOT-%08X",
1107                   (uint32) pdb_get_kickoff_time (sampass));
1108         slprintf (pwdlset_t, 13, "LCT-%08X",
1109                   (uint32) pdb_get_pass_last_set_time (sampass));
1110         slprintf (pwdlchg_t, 13, "CCT-%08X",
1111                   (uint32) pdb_get_pass_can_change_time (sampass));
1112         slprintf (pwdmchg_t, 13, "MCT-%08X",
1113                   (uint32) pdb_get_pass_must_change_time (sampass));
1114         safe_strcpy (full_name, pdb_get_fullname (sampass),
1115                      sizeof (full_name) - 1);
1116         safe_strcpy (acct_desc, pdb_get_acct_desc (sampass),
1117                      sizeof (acct_desc) - 1);
1118
1119 #if 0
1120
1121         /* Not sure what to do with these guys. -tpot */
1122
1123         dos_to_unix (full_name, True);
1124         dos_to_unix (acct_desc, True);
1125
1126 #endif
1127
1128         if (old) {
1129                 /* name */
1130                 if (strcmp (ENTRY_VAL (old, NPF_NAME), name)) {
1131                         need_to_modify = True;
1132                         set_single_attribute (obj, NPF_NAME, name,
1133                                               strlen (name), EN_MODIFIED);
1134                 }
1135
1136
1137                 /* uid */
1138                 if (pdb_get_uid (sampass) != -1) {
1139                         if (!ENTRY_VAL (old, NPF_UID)
1140                             || strcmp (ENTRY_VAL (old, NPF_UID), uid)) {
1141                                 need_to_modify = True;
1142                                 set_single_attribute (obj, NPF_UID, uid,
1143                                                       strlen (uid),
1144                                                       EN_MODIFIED);
1145                         }
1146                 }
1147
1148                 /* user_rid */
1149                 if (pdb_get_user_rid (sampass)) {
1150                         if (!ENTRY_VAL (old, NPF_USER_RID) ||
1151                             strcmp (ENTRY_VAL (old, NPF_USER_RID),
1152                                     user_rid)) {
1153                                 need_to_modify = True;
1154                                 set_single_attribute (obj, NPF_USER_RID,
1155                                                       user_rid,
1156                                                       strlen (user_rid),
1157                                                       EN_MODIFIED);
1158                         }
1159                 }
1160
1161                 /* smb_grpid */
1162                 if (pdb_get_gid (sampass) != -1) {
1163                         if (!ENTRY_VAL (old, NPF_SMB_GRPID) ||
1164                             strcmp (ENTRY_VAL (old, NPF_SMB_GRPID), gid)) {
1165                                 need_to_modify = True;
1166                                 set_single_attribute (obj, NPF_SMB_GRPID, gid,
1167                                                       strlen (gid),
1168                                                       EN_MODIFIED);
1169                         }
1170                 }
1171
1172                 /* group_rid */
1173                 if (pdb_get_group_rid (sampass)) {
1174                         if (!ENTRY_VAL (old, NPF_GROUP_RID) ||
1175                             strcmp (ENTRY_VAL (old, NPF_GROUP_RID),
1176                                     group_rid)) {
1177                                 need_to_modify = True;
1178                                 set_single_attribute (obj, NPF_GROUP_RID,
1179                                                       group_rid,
1180                                                       strlen (group_rid),
1181                                                       EN_MODIFIED);
1182                         }
1183                 }
1184
1185                 /* acb */
1186                 if (!ENTRY_VAL (old, NPF_ACB) ||
1187                     strcmp (ENTRY_VAL (old, NPF_ACB), acb)) {
1188                         need_to_modify = True;
1189                         set_single_attribute (obj, NPF_ACB, acb, strlen (acb),
1190                                               EN_MODIFIED);
1191                 }
1192
1193                 /* lmpwd */
1194                 if (!ENTRY_VAL (old, NPF_LMPWD) ||
1195                     strcmp (ENTRY_VAL (old, NPF_LMPWD), smb_passwd)) {
1196                         need_to_modify = True;
1197                         set_single_attribute (obj, NPF_LMPWD, smb_passwd,
1198                                               strlen (smb_passwd),
1199                                               EN_CRYPT | EN_MODIFIED);
1200                 }
1201
1202                 /* ntpwd */
1203                 if (!ENTRY_VAL (old, NPF_NTPWD) ||
1204                     strcmp (ENTRY_VAL (old, NPF_NTPWD), smb_nt_passwd)) {
1205                         need_to_modify = True;
1206                         set_single_attribute (obj, NPF_NTPWD, smb_nt_passwd,
1207                                               strlen (smb_nt_passwd),
1208                                               EN_CRYPT | EN_MODIFIED);
1209                 }
1210
1211                 /* logon_t */
1212                 if (pdb_get_logon_time (sampass) &&
1213                     (!ENTRY_VAL (old, NPF_LOGON_T) ||
1214                      strcmp (ENTRY_VAL (old, NPF_LOGON_T), logon_t))) {
1215                         need_to_modify = True;
1216                         set_single_attribute (obj, NPF_LOGON_T, logon_t,
1217                                               strlen (logon_t), EN_MODIFIED);
1218                 }
1219
1220                 /* logoff_t */
1221                 if (pdb_get_logoff_time (sampass) &&
1222                     (!ENTRY_VAL (old, NPF_LOGOFF_T) ||
1223                      strcmp (ENTRY_VAL (old, NPF_LOGOFF_T), logoff_t))) {
1224                         need_to_modify = True;
1225                         set_single_attribute (obj, NPF_LOGOFF_T, logoff_t,
1226                                               strlen (logoff_t), EN_MODIFIED);
1227                 }
1228
1229                 /* kick_t */
1230                 if (pdb_get_kickoff_time (sampass) &&
1231                     (!ENTRY_VAL (old, NPF_KICK_T) ||
1232                      strcmp (ENTRY_VAL (old, NPF_KICK_T), kickoff_t))) {
1233                         need_to_modify = True;
1234                         set_single_attribute (obj, NPF_KICK_T, kickoff_t,
1235                                               strlen (kickoff_t),
1236                                               EN_MODIFIED);
1237                 }
1238
1239                 /* pwdlset_t */
1240                 if (pdb_get_pass_last_set_time (sampass) &&
1241                     (!ENTRY_VAL (old, NPF_PWDLSET_T) ||
1242                      strcmp (ENTRY_VAL (old, NPF_PWDLSET_T), pwdlset_t))) {
1243                         need_to_modify = True;
1244                         set_single_attribute (obj, NPF_PWDLSET_T, pwdlset_t,
1245                                               strlen (pwdlset_t),
1246                                               EN_MODIFIED);
1247                 }
1248
1249                 /* pwdlchg_t */
1250                 if (pdb_get_pass_can_change_time (sampass) &&
1251                     (!ENTRY_VAL (old, NPF_PWDCCHG_T) ||
1252                      strcmp (ENTRY_VAL (old, NPF_PWDCCHG_T), pwdlchg_t))) {
1253                         need_to_modify = True;
1254                         set_single_attribute (obj, NPF_PWDCCHG_T, pwdlchg_t,
1255                                               strlen (pwdlchg_t),
1256                                               EN_MODIFIED);
1257                 }
1258
1259                 /* pwdmchg_t */
1260                 if (pdb_get_pass_must_change_time (sampass) &&
1261                     (!ENTRY_VAL (old, NPF_PWDMCHG_T) ||
1262                      strcmp (ENTRY_VAL (old, NPF_PWDMCHG_T), pwdmchg_t))) {
1263                         need_to_modify = True;
1264                         set_single_attribute (obj, NPF_PWDMCHG_T, pwdmchg_t,
1265                                               strlen (pwdmchg_t),
1266                                               EN_MODIFIED);
1267                 }
1268
1269                 /* full_name */
1270                 /* must support set, unset and change */
1271                 if ((pdb_get_fullname (sampass) &&
1272                      !ENTRY_VAL (old, NPF_FULL_NAME)) ||
1273                     (ENTRY_VAL (old, NPF_FULL_NAME) &&
1274                      !pdb_get_fullname (sampass)) ||
1275                     (ENTRY_VAL (old, NPF_FULL_NAME) &&
1276                      pdb_get_fullname (sampass) &&
1277                      strcmp (ENTRY_VAL (old, NPF_FULL_NAME), full_name))) {
1278                         need_to_modify = True;
1279                         set_single_attribute (obj, NPF_FULL_NAME, full_name,
1280                                               strlen (full_name),
1281                                               EN_MODIFIED);
1282                 }
1283
1284                 /* home_dir */
1285                 /* must support set, unset and change */
1286                 if ((pdb_get_homedir (sampass) &&
1287                      !ENTRY_VAL (old, NPF_HOME_DIR)) ||
1288                     (ENTRY_VAL (old, NPF_HOME_DIR) &&
1289                      !pdb_get_homedir (sampass)) ||
1290                     (ENTRY_VAL (old, NPF_HOME_DIR) &&
1291                      pdb_get_homedir (sampass) &&
1292                      strcmp (ENTRY_VAL (old, NPF_HOME_DIR),
1293                              pdb_get_homedir (sampass)))) {
1294                         need_to_modify = True;
1295                         set_single_attribute (obj, NPF_HOME_DIR,
1296                                               pdb_get_homedir (sampass),
1297                                               strlen (pdb_get_homedir
1298                                                       (sampass)),
1299                                               EN_MODIFIED);
1300                 }
1301
1302                 /* dir_drive */
1303                 /* must support set, unset and change */
1304                 if ((pdb_get_dir_drive (sampass) &&
1305                      !ENTRY_VAL (old, NPF_DIR_DRIVE)) ||
1306                     (ENTRY_VAL (old, NPF_DIR_DRIVE) &&
1307                      !pdb_get_dir_drive (sampass)) ||
1308                     (ENTRY_VAL (old, NPF_DIR_DRIVE) &&
1309                      pdb_get_dir_drive (sampass) &&
1310                      strcmp (ENTRY_VAL (old, NPF_DIR_DRIVE),
1311                              pdb_get_dir_drive (sampass)))) {
1312                         need_to_modify = True;
1313                         set_single_attribute (obj, NPF_DIR_DRIVE,
1314                                               pdb_get_dir_drive (sampass),
1315                                               strlen (pdb_get_dir_drive
1316                                                       (sampass)),
1317                                               EN_MODIFIED);
1318                 }
1319
1320                 /* logon_script */
1321                 /* must support set, unset and change */
1322                 if (((pdb_get_logon_script (sampass) &&
1323                       !ENTRY_VAL (old, NPF_LOGON_SCRIPT)) ||
1324                      ((ENTRY_VAL (old, NPF_LOGON_SCRIPT) &&
1325                        (!pdb_get_logon_script (sampass)))) ||
1326                      ((ENTRY_VAL (old, NPF_LOGON_SCRIPT) &&
1327                        pdb_get_logon_script (sampass) &&
1328                        strcmp (ENTRY_VAL (old, NPF_LOGON_SCRIPT),
1329                                pdb_get_logon_script (sampass)))))) {
1330                         need_to_modify = True;
1331                         set_single_attribute (obj, NPF_LOGON_SCRIPT,
1332                                               pdb_get_logon_script (sampass),
1333                                               strlen (pdb_get_logon_script
1334                                                       (sampass)),
1335                                               EN_MODIFIED);
1336                 }
1337
1338                 /* profile_path */
1339                 /* must support set, unset and change */
1340                 if ((pdb_get_profile_path (sampass) &&
1341                      !ENTRY_VAL (old, NPF_PROFILE_PATH)) ||
1342                     (ENTRY_VAL (old, NPF_PROFILE_PATH) &&
1343                      !pdb_get_profile_path (sampass)) ||
1344                     (ENTRY_VAL (old, NPF_PROFILE_PATH) &&
1345                      pdb_get_profile_path (sampass) &&
1346                      strcmp (ENTRY_VAL (old, NPF_PROFILE_PATH),
1347                              pdb_get_profile_path (sampass)))) {
1348                         need_to_modify = True;
1349                         set_single_attribute (obj, NPF_PROFILE_PATH,
1350                                               pdb_get_profile_path (sampass),
1351                                               strlen (pdb_get_profile_path
1352                                                       (sampass)),
1353                                               EN_MODIFIED);
1354                 }
1355
1356                 /* acct_desc */
1357                 /* must support set, unset and change */
1358                 if ((pdb_get_acct_desc (sampass) &&
1359                      !ENTRY_VAL (old, NPF_ACCT_DESC)) ||
1360                     (ENTRY_VAL (old, NPF_ACCT_DESC) &&
1361                      !pdb_get_acct_desc (sampass)) ||
1362                     (ENTRY_VAL (old, NPF_ACCT_DESC) &&
1363                      pdb_get_acct_desc (sampass) &&
1364                      strcmp (ENTRY_VAL (old, NPF_ACCT_DESC), acct_desc))) {
1365                         need_to_modify = True;
1366                         set_single_attribute (obj, NPF_ACCT_DESC, acct_desc,
1367                                               strlen (acct_desc),
1368                                               EN_MODIFIED);
1369                 }
1370
1371                 /* workstations */
1372                 /* must support set, unset and change */
1373                 if ((pdb_get_workstations (sampass) &&
1374                      !ENTRY_VAL (old, NPF_WORKSTATIONS)) ||
1375                     (ENTRY_VAL (old, NPF_WORKSTATIONS) &&
1376                      !pdb_get_workstations (sampass)) ||
1377                     (ENTRY_VAL (old, NPF_WORKSTATIONS) &&
1378                      (pdb_get_workstations (sampass)) &&
1379                      strcmp (ENTRY_VAL (old, NPF_WORKSTATIONS),
1380                              pdb_get_workstations (sampass)))) {
1381                         need_to_modify = True;
1382                         set_single_attribute (obj, NPF_WORKSTATIONS,
1383                                               pdb_get_workstations (sampass),
1384                                               strlen (pdb_get_workstations
1385                                                       (sampass)),
1386                                               EN_MODIFIED);
1387                 }
1388
1389                 /* hours */
1390                 if ((pdb_get_hours_len (sampass) !=
1391                      ENTRY_LEN (old, NPF_HOURS))
1392                     || memcmp (pdb_get_hours (sampass),
1393                                ENTRY_VAL (old, NPF_HOURS), ENTRY_LEN (old,
1394                                                                       NPF_HOURS)))
1395                 {
1396                         need_to_modify = True;
1397                         /* set_single_attribute will add 1 for len ... */
1398                         set_single_attribute (obj, NPF_HOURS,
1399                                               pdb_get_hours (sampass),
1400                                               pdb_get_hours_len (sampass) - 1,
1401                                               EN_MODIFIED);
1402                 }
1403         } else {
1404                 const char *homedir, *dirdrive, *logon_script, *profile_path,
1405                         *workstations;
1406
1407                 *empty = '\0';  /* empty string */
1408
1409                 set_single_attribute (obj, NPF_NAME, name, strlen (name), 0);
1410                 set_single_attribute (obj, NPF_UID, uid, strlen (uid), 0);
1411                 set_single_attribute (obj, NPF_USER_RID, user_rid,
1412                                       strlen (user_rid), 0);
1413                 set_single_attribute (obj, NPF_SMB_GRPID, gid, strlen (gid),
1414                                       0);
1415                 set_single_attribute (obj, NPF_GROUP_RID, group_rid,
1416                                       strlen (group_rid), 0);
1417                 set_single_attribute (obj, NPF_ACB, acb, strlen (acb), 0);
1418                 set_single_attribute (obj, NPF_LMPWD, smb_passwd,
1419                                       strlen (smb_passwd), EN_CRYPT);
1420                 set_single_attribute (obj, NPF_NTPWD, smb_nt_passwd,
1421                                       strlen (smb_nt_passwd), EN_CRYPT);
1422                 set_single_attribute (obj, NPF_LOGON_T, logon_t,
1423                                       strlen (logon_t), 0);
1424                 set_single_attribute (obj, NPF_LOGOFF_T, logoff_t,
1425                                       strlen (logoff_t), 0);
1426                 set_single_attribute (obj, NPF_KICK_T, kickoff_t,
1427                                       strlen (kickoff_t), 0);
1428                 set_single_attribute (obj, NPF_PWDLSET_T, pwdlset_t,
1429                                       strlen (pwdlset_t), 0);
1430                 set_single_attribute (obj, NPF_PWDCCHG_T, pwdlchg_t,
1431                                       strlen (pwdlchg_t), 0);
1432                 set_single_attribute (obj, NPF_PWDMCHG_T, pwdmchg_t,
1433                                       strlen (pwdmchg_t), 0);
1434                 set_single_attribute (obj, NPF_FULL_NAME,
1435                                       full_name, strlen (full_name), 0);
1436
1437                 if (!(homedir = pdb_get_homedir (sampass)))
1438                         homedir = empty;
1439
1440                 set_single_attribute (obj, NPF_HOME_DIR,
1441                                       homedir, strlen (homedir), 0);
1442
1443                 if (!(dirdrive = pdb_get_dir_drive (sampass)))
1444                         dirdrive = empty;
1445
1446                 set_single_attribute (obj, NPF_DIR_DRIVE,
1447                                       dirdrive, strlen (dirdrive), 0);
1448
1449                 if (!(logon_script = pdb_get_logon_script (sampass)))
1450                         logon_script = empty;
1451
1452                 set_single_attribute (obj, NPF_LOGON_SCRIPT,
1453                                       logon_script, strlen (logon_script), 0);
1454
1455                 if (!(profile_path = pdb_get_profile_path (sampass)))
1456                         profile_path = empty;
1457
1458                 set_single_attribute (obj, NPF_PROFILE_PATH,
1459                                       profile_path, strlen (profile_path), 0);
1460
1461                 set_single_attribute (obj, NPF_ACCT_DESC,
1462                                       acct_desc, strlen (acct_desc), 0);
1463
1464                 if (!(workstations = pdb_get_workstations (sampass)))
1465                         workstations = empty;
1466
1467                 set_single_attribute (obj, NPF_WORKSTATIONS,
1468                                       workstations, strlen (workstations), 0);
1469
1470                 /* set_single_attribute will add 1 for len ... */
1471                 set_single_attribute (obj, NPF_HOURS,
1472                                       pdb_get_hours (sampass),
1473                                       pdb_get_hours_len (sampass) - 1, 0);
1474         }
1475
1476         return need_to_modify;
1477 }
1478
1479 /***************************************************************
1480  calls nis_list, returns results.
1481  ****************************************************************/
1482 static nis_result *nisp_get_nis_list (const char *nisname, unsigned int flags)
1483 {
1484         nis_result *result;
1485         int i;
1486
1487         if (!flags)
1488                 flags = FOLLOW_LINKS | FOLLOW_PATH | EXPAND_NAME |
1489                         HARD_LOOKUP;
1490
1491         for (i = 0; i < 2; i++) {
1492                 alarm (60);     /* hopefully ok for long searches */
1493                 result = nis_list (nisname, flags, NULL, NULL);
1494
1495                 alarm (0);
1496                 CatchSignal (SIGALRM, SIGNAL_CAST SIG_DFL);
1497
1498                 if (!(flags & MASTER_ONLY) && NIS_RES_NUMOBJ (result) <= 0) {
1499                         /* nis replicas are not in sync perhaps?
1500                          * this can happen, if account was just added.
1501                          */
1502                         DEBUG (10, ("will try master only\n"));
1503                         nis_freeresult (result);
1504                         flags |= MASTER_ONLY;
1505                 } else
1506                         break;
1507         }
1508         return result;
1509 }
1510
1511 static void free_private_data(void **vp)
1512 {
1513         struct nisplus_private_info **private = (struct nisplus_private_info **)vp;
1514
1515         if ((*private)->result) {
1516                 nis_freeresult ((*private)->result);
1517         }
1518
1519         free(*private);
1520
1521         /* No need to free any further, as it is talloc()ed */
1522 }
1523
1524 NTSTATUS pdb_init_nisplussam (PDB_CONTEXT * pdb_context,
1525                               PDB_METHODS ** pdb_method, const char *location)
1526 {
1527         NTSTATUS nt_status;
1528         struct nisplus_private_info *private = malloc (sizeof (struct nisplus_private_info));
1529
1530         ZERO_STRUCT(private);
1531         p->location = talloc_strdup(pdb_context->mem_ctx, location);
1532
1533         if (!NT_STATUS_IS_OK
1534             (nt_status =
1535              make_pdb_methods (pdb_context->mem_ctx, pdb_method))) {
1536                 return nt_status;
1537         }
1538
1539         (*pdb_method)->name = "nisplussam";
1540
1541         /* Functions your pdb module doesn't provide should be set 
1542          * to NULL */
1543
1544         (*pdb_method)->setsampwent = nisplussam_setsampwent;
1545         (*pdb_method)->endsampwent = nisplussam_endsampwent;
1546         (*pdb_method)->getsampwent = nisplussam_getsampwent;
1547         (*pdb_method)->getsampwnam = nisplussam_getsampwnam;
1548         (*pdb_method)->getsampwsid = nisplussam_getsampwsid;
1549         (*pdb_method)->add_sam_account = nisplussam_add_sam_account;
1550         (*pdb_method)->update_sam_account = nisplussam_update_sam_account;
1551         (*pdb_method)->delete_sam_account = nisplussam_delete_sam_account;
1552         (*pdb_method)->free_private_data = free_private_data;
1553         (*pdb_method)->private_data = private;
1554
1555         return NT_STATUS_OK;
1556 }
1557
1558 #else
1559 NTSTATUS pdb_init_nisplussam (PDB_CONTEXT * c, PDB_METHODS ** m,
1560                               const char *l)
1561 {
1562         DEBUG (0, ("nisplus sam not compiled in!\n"));
1563         return NT_STATUS_UNSUCCESSFUL;
1564 }
1565 #endif /* WITH_NISPLUS_SAM */