1 /*        $NetBSD: slapd-modify.c,v 1.3 2021/08/14 16:15:03 christos Exp $      */
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2021 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 
18 #include <sys/cdefs.h>
19 __RCSID("$NetBSD: slapd-modify.c,v 1.3 2021/08/14 16:15:03 christos Exp $");
20 
21 #include "portable.h"
22 
23 #include <stdio.h>
24 
25 #include "ac/stdlib.h"
26 
27 #include "ac/ctype.h"
28 #include "ac/param.h"
29 #include "ac/socket.h"
30 #include "ac/string.h"
31 #include "ac/unistd.h"
32 #include "ac/wait.h"
33 
34 #include "ldap.h"
35 #include "lutil.h"
36 
37 #include "slapd-common.h"
38 
39 #define LOOPS       100
40 
41 static void
42 do_modify( struct tester_conn_args *config, char *entry,
43                     char *attr, char *value, int friendly );
44 
45 
46 static void
usage(char * name,int opt)47 usage( char *name, int opt )
48 {
49           if ( opt ) {
50                     fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
51                               name, opt );
52           }
53 
54           fprintf( stderr, "usage: %s " TESTER_COMMON_HELP
55                     "-a <attr:val> "
56                     "-e <entry> "
57                     "[-F]\n",
58                     name );
59           exit( EXIT_FAILURE );
60 }
61 
62 int
main(int argc,char ** argv)63 main( int argc, char **argv )
64 {
65           int                 i;
66           char                *entry = NULL;
67           char                *ava = NULL;
68           char                *value = NULL;
69           int                 friendly = 0;
70           struct tester_conn_args       *config;
71 
72           config = tester_init( "slapd-modify", TESTER_MODIFY );
73 
74           while ( ( i = getopt( argc, argv, TESTER_COMMON_OPTS "a:e:F" ) ) != EOF )
75           {
76                     switch ( i ) {
77                     case 'F':
78                               friendly++;
79                               break;
80 
81                     case 'i':
82                               /* ignored (!) by now */
83                               break;
84 
85                     case 'e':           /* entry to modify */
86                               entry = optarg;
87                               break;
88 
89                     case 'a':
90                               ava = optarg;
91                               break;
92 
93                     default:
94                               if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) {
95                                         break;
96                               }
97                               usage( argv[0], i );
98                               break;
99                     }
100           }
101 
102           if (( entry == NULL ) || ( ava == NULL ))
103                     usage( argv[0], 0 );
104 
105           if ( *entry == '\0' ) {
106 
107                     fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
108                                         argv[0] );
109                     exit( EXIT_FAILURE );
110 
111           }
112           if ( *ava  == '\0' ) {
113                     fprintf( stderr, "%s: invalid EMPTY AVA.\n",
114                                         argv[0] );
115                     exit( EXIT_FAILURE );
116           }
117 
118           if ( !( value = strchr( ava, ':' ))) {
119                     fprintf( stderr, "%s: invalid AVA.\n",
120                                         argv[0] );
121                     exit( EXIT_FAILURE );
122           }
123           *value++ = '\0';
124           while ( *value && isspace( (unsigned char) *value ))
125                     value++;
126 
127           tester_config_finish( config );
128 
129           for ( i = 0; i < config->outerloops; i++ ) {
130                     do_modify( config, entry, ava, value, friendly );
131           }
132 
133           exit( EXIT_SUCCESS );
134 }
135 
136 
137 static void
do_modify(struct tester_conn_args * config,char * entry,char * attr,char * value,int friendly)138 do_modify( struct tester_conn_args *config,
139           char *entry, char* attr, char* value, int friendly )
140 {
141           LDAP      *ld = NULL;
142           int       i = 0, do_retry = config->retries;
143           int     rc = LDAP_SUCCESS;
144 
145           struct ldapmod mod;
146           struct ldapmod *mods[2];
147           char *values[2];
148 
149           values[0] = value;
150           values[1] = NULL;
151           mod.mod_op = LDAP_MOD_ADD;
152           mod.mod_type = attr;
153           mod.mod_values = values;
154           mods[0] = &mod;
155           mods[1] = NULL;
156 
157 retry:;
158           if ( ld == NULL ) {
159                     tester_init_ld( &ld, config, 0 );
160           }
161 
162           if ( do_retry == config->retries ) {
163                     fprintf( stderr, "PID=%ld - Modify(%d): entry=\"%s\".\n",
164                               (long) pid, config->loops, entry );
165           }
166 
167           for ( ; i < config->loops; i++ ) {
168                     mod.mod_op = LDAP_MOD_ADD;
169                     rc = ldap_modify_ext_s( ld, entry, mods, NULL, NULL );
170                     if ( rc != LDAP_SUCCESS ) {
171                               tester_ldap_error( ld, "ldap_modify_ext_s", NULL );
172                               switch ( rc ) {
173                               case LDAP_TYPE_OR_VALUE_EXISTS:
174                                         /* NOTE: this likely means
175                                          * the second modify failed
176                                          * during the previous round... */
177                                         if ( !friendly ) {
178                                                   goto done;
179                                         }
180                                         break;
181 
182                               case LDAP_BUSY:
183                               case LDAP_UNAVAILABLE:
184                                         if ( do_retry > 0 ) {
185                                                   do_retry--;
186                                                   goto retry;
187                                         }
188                                         /* fall thru */
189 
190                               default:
191                                         goto done;
192                               }
193                     }
194 
195                     mod.mod_op = LDAP_MOD_DELETE;
196                     rc = ldap_modify_ext_s( ld, entry, mods, NULL, NULL );
197                     if ( rc != LDAP_SUCCESS ) {
198                               tester_ldap_error( ld, "ldap_modify_ext_s", NULL );
199                               switch ( rc ) {
200                               case LDAP_NO_SUCH_ATTRIBUTE:
201                                         /* NOTE: this likely means
202                                          * the first modify failed
203                                          * during the previous round... */
204                                         if ( !friendly ) {
205                                                   goto done;
206                                         }
207                                         break;
208 
209                               case LDAP_BUSY:
210                               case LDAP_UNAVAILABLE:
211                                         if ( do_retry > 0 ) {
212                                                   do_retry--;
213                                                   goto retry;
214                                         }
215                                         /* fall thru */
216 
217                               default:
218                                         goto done;
219                               }
220                     }
221 
222           }
223 
224 done:;
225           fprintf( stderr, "  PID=%ld - Modify done (%d).\n", (long) pid, rc );
226 
227           ldap_unbind_ext( ld, NULL, NULL );
228 }
229 
230 
231