Initial import
[samba] / source / lib / smbldap_util.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    Copyright (C) Jean François Micouleau        1998
5    Copyright (C) Gerald Carter                  2001-2003
6    Copyright (C) Shahms King                    2001
7    Copyright (C) Andrew Bartlett                2002-2003
8    Copyright (C) Stefan (metze) Metzmacher      2002-2003
9     
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23    
24 */
25
26 #include "includes.h"
27 #include "smbldap.h"
28
29 /**********************************************************************
30  Add the account-policies below the sambaDomain object to LDAP, 
31 *********************************************************************/
32 static NTSTATUS add_new_domain_account_policies(struct smbldap_state *ldap_state,
33                                                 const char *domain_name)
34 {
35         NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
36         int i, rc;
37         uint32 policy_default;
38         const char *policy_attr = NULL;
39         pstring dn;
40         LDAPMod **mods = NULL;
41
42         DEBUG(3,("Adding new account policies for domain\n"));
43         
44         pstr_sprintf(dn, "%s=%s,%s", 
45                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
46                 domain_name, lp_ldap_suffix());
47
48         for (i=1; decode_account_policy_name(i) != NULL; i++) {
49
50                 pstring val;
51
52                 policy_attr = get_account_policy_attr(i);
53                 if (!policy_attr) {
54                         DEBUG(0,("add_new_domain_account_policies: ops. no policy!\n"));
55                         continue;
56                 }
57
58                 if (!account_policy_get_default(i, &policy_default)) {
59                         DEBUG(0,("add_new_domain_account_policies: failed to get default account policy\n"));
60                         return ntstatus;
61                 }
62
63                 DEBUG(10,("add_new_domain_account_policies: adding \"%s\" with value: %d\n", policy_attr, policy_default));
64
65                 pstr_sprintf(val, "%d", policy_default); 
66
67                 smbldap_set_mod( &mods, LDAP_MOD_REPLACE, policy_attr, val);
68
69                 rc = smbldap_modify(ldap_state, dn, mods);
70
71                 if (rc!=LDAP_SUCCESS) {
72                         char *ld_error = NULL;
73                         ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
74                         DEBUG(1,("failed to add account policies to dn= %s with: %s\n\t%s\n",
75                                 dn, ldap_err2string(rc),
76                                 ld_error ? ld_error : "unknown"));
77                         SAFE_FREE(ld_error);
78                         ldap_mods_free(mods, True);
79                         return ntstatus;
80                 }
81         }
82
83         ldap_mods_free(mods, True);
84
85         return NT_STATUS_OK;
86 }
87
88 /**********************************************************************
89  Add the sambaDomain to LDAP, so we don't have to search for this stuff
90  again.  This is a once-add operation for now.
91
92  TODO:  Add other attributes, and allow modification.
93 *********************************************************************/
94 static NTSTATUS add_new_domain_info(struct smbldap_state *ldap_state, 
95                                     const char *domain_name) 
96 {
97         fstring sid_string;
98         fstring algorithmic_rid_base_string;
99         pstring filter, dn;
100         LDAPMod **mods = NULL;
101         int rc;
102         int ldap_op;
103         LDAPMessage *result = NULL;
104         int num_result;
105         const char **attr_list;
106         uid_t u_low, u_high;
107         gid_t g_low, g_high;
108         uint32 rid_low, rid_high;
109
110         slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))", 
111                   get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
112                   domain_name, LDAP_OBJ_DOMINFO);
113
114         attr_list = get_attr_list( dominfo_attr_list );
115         rc = smbldap_search_suffix(ldap_state, filter, attr_list, &result);
116         free_attr_list( attr_list );
117
118         if (rc != LDAP_SUCCESS) {
119                 return NT_STATUS_UNSUCCESSFUL;
120         }
121
122         num_result = ldap_count_entries(ldap_state->ldap_struct, result);
123         
124         if (num_result > 1) {
125                 DEBUG (0, ("More than domain with that name exists: bailing out!\n"));
126                 ldap_msgfree(result);
127                 return NT_STATUS_UNSUCCESSFUL;
128         }
129         
130         /* Check if we need to add an entry */
131         DEBUG(3,("Adding new domain\n"));
132         ldap_op = LDAP_MOD_ADD;
133
134         pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
135                 domain_name, lp_ldap_suffix());
136
137         /* Free original search */
138         ldap_msgfree(result);
139
140         /* make the changes - the entry *must* not already have samba attributes */
141         smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
142                 domain_name);
143
144         /* If we don't have an entry, then ask secrets.tdb for what it thinks.  
145            It may choose to make it up */
146
147         sid_to_string(sid_string, get_global_sam_sid());
148         smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), sid_string);
149
150         slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string) - 1, "%i", algorithmic_rid_base());
151         smbldap_set_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), 
152                         algorithmic_rid_base_string);
153         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
154         
155         /* add the sambaNext[User|Group]Rid attributes if the idmap ranges are set.
156            TODO: fix all the places where the line between idmap and normal operations
157            needed by smbd gets fuzzy   --jerry 2003-08-11                              */
158         
159         if ( lp_idmap_uid(&u_low, &u_high) && lp_idmap_gid(&g_low, &g_high)
160                 && get_free_rid_range(&rid_low, &rid_high) ) 
161         {
162                 fstring rid_str;
163                 
164                 fstr_sprintf( rid_str, "%i", rid_high|USER_RID_TYPE );
165                 DEBUG(10,("setting next available user rid [%s]\n", rid_str));
166                 smbldap_set_mod(&mods, LDAP_MOD_ADD, 
167                         get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), 
168                         rid_str);
169                         
170                 fstr_sprintf( rid_str, "%i", rid_high|GROUP_RID_TYPE );
171                 DEBUG(10,("setting next available group rid [%s]\n", rid_str));
172                 smbldap_set_mod(&mods, LDAP_MOD_ADD, 
173                         get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), 
174                         rid_str);
175                 
176         }
177
178
179         switch(ldap_op)
180         {
181         case LDAP_MOD_ADD: 
182                 rc = smbldap_add(ldap_state, dn, mods);
183                 break;
184         case LDAP_MOD_REPLACE: 
185                 rc = smbldap_modify(ldap_state, dn, mods);
186                 break;
187         default:        
188                 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
189                 return NT_STATUS_INVALID_PARAMETER;
190         }
191         
192         if (rc!=LDAP_SUCCESS) {
193                 char *ld_error = NULL;
194                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
195                 DEBUG(1,("failed to %s domain dn= %s with: %s\n\t%s\n",
196                        ldap_op == LDAP_MOD_ADD ? "add" : "modify",
197                        dn, ldap_err2string(rc),
198                        ld_error?ld_error:"unknown"));
199                 SAFE_FREE(ld_error);
200
201                 ldap_mods_free(mods, True);
202                 return NT_STATUS_UNSUCCESSFUL;
203         }
204
205         DEBUG(2,("added: domain = %s in the LDAP database\n", domain_name));
206         ldap_mods_free(mods, True);
207         return NT_STATUS_OK;
208 }
209
210 /**********************************************************************
211 Search for the domain info entry
212 *********************************************************************/
213 NTSTATUS smbldap_search_domain_info(struct smbldap_state *ldap_state,
214                                     LDAPMessage ** result, const char *domain_name,
215                                     BOOL try_add)
216 {
217         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
218         pstring filter;
219         int rc;
220         const char **attr_list;
221         int count;
222
223         pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
224                 LDAP_OBJ_DOMINFO,
225                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
226                 domain_name);
227
228         DEBUG(2, ("Searching for:[%s]\n", filter));
229
230         attr_list = get_attr_list( dominfo_attr_list );
231         rc = smbldap_search_suffix(ldap_state, filter, attr_list , result);
232         free_attr_list( attr_list );
233
234         if (rc != LDAP_SUCCESS) {
235                 DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
236                 DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
237                 goto failed;
238         }
239
240         count = ldap_count_entries(ldap_state->ldap_struct, *result);
241
242         if (count == 1)
243                 return NT_STATUS_OK;
244
245         ldap_msgfree(*result);
246         *result = NULL;
247         
248         if (count < 1) {
249
250                 DEBUG(3, ("Got no domain info entries for domain\n"));
251
252                 if (!try_add)
253                         goto failed;
254
255                 status = add_new_domain_info(ldap_state, domain_name);
256                 if (!NT_STATUS_IS_OK(status)) {
257                         DEBUG(0, ("Adding domain info for %s failed with %s\n", 
258                                 domain_name, nt_errstr(status)));
259                         goto failed;
260                 }
261                         
262                 status = add_new_domain_account_policies(ldap_state, domain_name);
263                 if (!NT_STATUS_IS_OK(status)) {
264                         DEBUG(0, ("Adding domain account policies for %s failed with %s\n", 
265                                 domain_name, nt_errstr(status)));
266                         goto failed;
267                 }
268
269                 return smbldap_search_domain_info(ldap_state, result, domain_name, False);
270                 
271         } 
272         
273         if (count > 1 ) {
274         
275                 DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
276                           count, domain_name));
277                 goto failed;
278         }
279
280 failed:
281         return status;
282         
283 }
284