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