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