1 1.3 christos /* $NetBSD: ldapmodrdn.c,v 1.4 2025/09/05 21:16:13 christos Exp $ */ 2 1.2 christos 3 1.1 lukem /* ldapmodrdn.c - generic program to modify an entry's RDN using LDAP */ 4 1.2 christos /* $OpenLDAP$ */ 5 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 1.1 lukem * 7 1.4 christos * Copyright 1998-2024 The OpenLDAP Foundation. 8 1.1 lukem * Portions Copyright 1998-2003 Kurt D. Zeilenga. 9 1.1 lukem * Portions Copyright 1998-2001 Net Boolean Incorporated. 10 1.1 lukem * Portions Copyright 2001-2003 IBM Corporation. 11 1.1 lukem * All rights reserved. 12 1.1 lukem * 13 1.1 lukem * Redistribution and use in source and binary forms, with or without 14 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP 15 1.1 lukem * Public License. 16 1.1 lukem * 17 1.1 lukem * A copy of this license is available in the file LICENSE in the 18 1.1 lukem * top-level directory of the distribution or, alternatively, at 19 1.1 lukem * <http://www.OpenLDAP.org/license.html>. 20 1.1 lukem */ 21 1.1 lukem /* Portions Copyright 1999, Juan C. Gomez, All rights reserved. 22 1.1 lukem * This software is not subject to any license of Silicon Graphics 23 1.1 lukem * Inc. or Purdue University. 24 1.1 lukem * 25 1.1 lukem * Redistribution and use in source and binary forms are permitted 26 1.1 lukem * without restriction or fee of any kind as long as this notice 27 1.1 lukem * is preserved. 28 1.1 lukem */ 29 1.1 lukem /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan. 30 1.1 lukem * All rights reserved. 31 1.1 lukem * 32 1.1 lukem * Redistribution and use in source and binary forms are permitted 33 1.1 lukem * provided that this notice is preserved and that due credit is given 34 1.1 lukem * to the University of Michigan at Ann Arbor. The name of the 35 1.1 lukem * University may not be used to endorse or promote products derived 36 1.1 lukem * from this software without specific prior written permission. This 37 1.1 lukem * software is provided ``as is'' without express or implied warranty. 38 1.1 lukem */ 39 1.1 lukem /* ACKNOWLEDGEMENTS: 40 1.1 lukem * This work was originally developed by the University of Michigan 41 1.1 lukem * (as part of U-MICH LDAP). Additional significant contributors 42 1.1 lukem * include: 43 1.2 christos * Kurt D. Zeilenga 44 1.2 christos * Juan C Gomez 45 1.1 lukem */ 46 1.1 lukem 47 1.1 lukem 48 1.2 christos #include <sys/cdefs.h> 49 1.3 christos __RCSID("$NetBSD: ldapmodrdn.c,v 1.4 2025/09/05 21:16:13 christos Exp $"); 50 1.2 christos 51 1.1 lukem #include "portable.h" 52 1.1 lukem 53 1.1 lukem #include <stdio.h> 54 1.1 lukem 55 1.1 lukem #include <ac/stdlib.h> 56 1.1 lukem 57 1.1 lukem #include <ac/ctype.h> 58 1.1 lukem #include <ac/string.h> 59 1.1 lukem #include <ac/unistd.h> 60 1.1 lukem #include <ac/socket.h> 61 1.1 lukem #include <ac/time.h> 62 1.1 lukem 63 1.1 lukem #include <ldap.h> 64 1.1 lukem #include "lutil.h" 65 1.1 lukem #include "lutil_ldap.h" 66 1.1 lukem #include "ldap_defaults.h" 67 1.1 lukem 68 1.1 lukem #include "common.h" 69 1.1 lukem 70 1.1 lukem 71 1.1 lukem static char *newSuperior = NULL; 72 1.1 lukem static int remove_old_RDN = 0; 73 1.1 lukem 74 1.1 lukem 75 1.1 lukem static int domodrdn( 76 1.2 christos LDAP *ld, 77 1.2 christos char *dn, 78 1.2 christos char *rdn, 79 1.2 christos char *newSuperior, 80 1.2 christos int remove ); /* flag: remove old RDN */ 81 1.1 lukem 82 1.1 lukem void 83 1.1 lukem usage( void ) 84 1.1 lukem { 85 1.1 lukem fprintf( stderr, _("Rename LDAP entries\n\n")); 86 1.1 lukem fprintf( stderr, _("usage: %s [options] [dn rdn]\n"), prog); 87 1.1 lukem fprintf( stderr, _(" dn rdn: If given, rdn will replace the RDN of the entry specified by DN\n")); 88 1.1 lukem fprintf( stderr, _(" If not given, the list of modifications is read from stdin or\n")); 89 1.1 lukem fprintf( stderr, _(" from the file specified by \"-f file\" (see man page).\n")); 90 1.1 lukem fprintf( stderr, _("Rename options:\n")); 91 1.2 christos fprintf( stderr, _(" -c continuous operation mode (do not stop on errors)\n")); 92 1.2 christos fprintf( stderr, _(" -f file read operations from `file'\n")); 93 1.2 christos fprintf( stderr, _(" -M enable Manage DSA IT control (-MM to make critical)\n")); 94 1.2 christos fprintf( stderr, _(" -P version protocol version (default: 3)\n")); 95 1.2 christos fprintf( stderr, _(" -r remove old RDN\n")); 96 1.1 lukem fprintf( stderr, _(" -s newsup new superior entry\n")); 97 1.1 lukem tool_common_usage(); 98 1.1 lukem exit( EXIT_FAILURE ); 99 1.1 lukem } 100 1.1 lukem 101 1.1 lukem 102 1.1 lukem const char options[] = "rs:" 103 1.4 christos "cd:D:e:f:H:IMnNO:o:P:QR:U:vVw:WxX:y:Y:Z"; 104 1.1 lukem 105 1.1 lukem int 106 1.1 lukem handle_private_option( int i ) 107 1.1 lukem { 108 1.1 lukem switch ( i ) { 109 1.1 lukem #if 0 110 1.1 lukem int crit; 111 1.1 lukem char *control, *cvalue; 112 1.1 lukem case 'E': /* modrdn extensions */ 113 1.1 lukem if( protocol == LDAP_VERSION2 ) { 114 1.1 lukem fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"), 115 1.1 lukem prog, version ); 116 1.1 lukem exit( EXIT_FAILURE ); 117 1.1 lukem } 118 1.1 lukem 119 1.1 lukem /* should be extended to support comma separated list of 120 1.1 lukem * [!]key[=value] parameters, e.g. -E !foo,bar=567 121 1.1 lukem */ 122 1.1 lukem 123 1.1 lukem crit = 0; 124 1.1 lukem cvalue = NULL; 125 1.1 lukem if( optarg[0] == '!' ) { 126 1.1 lukem crit = 1; 127 1.1 lukem optarg++; 128 1.1 lukem } 129 1.1 lukem 130 1.3 christos control = optarg; 131 1.1 lukem if ( (cvalue = strchr( control, '=' )) != NULL ) { 132 1.1 lukem *cvalue++ = '\0'; 133 1.1 lukem } 134 1.1 lukem fprintf( stderr, _("Invalid modrdn extension name: %s\n"), control ); 135 1.1 lukem usage(); 136 1.1 lukem #endif 137 1.1 lukem 138 1.1 lukem case 'r': /* remove old RDN */ 139 1.2 christos remove_old_RDN++; 140 1.2 christos break; 141 1.1 lukem 142 1.1 lukem case 's': /* newSuperior */ 143 1.1 lukem if( protocol == LDAP_VERSION2 ) { 144 1.1 lukem fprintf( stderr, _("%s: -X incompatible with LDAPv%d\n"), 145 1.1 lukem prog, protocol ); 146 1.1 lukem exit( EXIT_FAILURE ); 147 1.1 lukem } 148 1.3 christos newSuperior = optarg; 149 1.2 christos protocol = LDAP_VERSION3; 150 1.2 christos break; 151 1.1 lukem 152 1.1 lukem default: 153 1.1 lukem return 0; 154 1.1 lukem } 155 1.1 lukem return 1; 156 1.1 lukem } 157 1.1 lukem 158 1.1 lukem 159 1.1 lukem int 160 1.1 lukem main(int argc, char **argv) 161 1.1 lukem { 162 1.2 christos char *entrydn = NULL, *rdn = NULL, buf[ 4096 ]; 163 1.2 christos FILE *fp = NULL; 164 1.2 christos LDAP *ld = NULL; 165 1.1 lukem int rc, retval, havedn; 166 1.1 lukem 167 1.2 christos tool_init( TOOL_MODRDN ); 168 1.2 christos prog = lutil_progname( "ldapmodrdn", argc, argv ); 169 1.1 lukem 170 1.1 lukem tool_args( argc, argv ); 171 1.1 lukem 172 1.2 christos havedn = 0; 173 1.2 christos if (argc - optind == 2) { 174 1.2 christos if (( rdn = strdup( argv[argc - 1] )) == NULL ) { 175 1.2 christos perror( "strdup" ); 176 1.2 christos retval = EXIT_FAILURE; 177 1.2 christos goto fail; 178 1.2 christos } 179 1.2 christos if (( entrydn = strdup( argv[argc - 2] )) == NULL ) { 180 1.2 christos perror( "strdup" ); 181 1.2 christos retval = EXIT_FAILURE; 182 1.2 christos goto fail; 183 1.2 christos } 184 1.2 christos ++havedn; 185 1.2 christos } else if ( argc - optind != 0 ) { 186 1.2 christos fprintf( stderr, _("%s: invalid number of arguments (%d), only two allowed\n"), prog, argc-optind ); 187 1.2 christos usage(); 188 1.1 lukem } 189 1.2 christos 190 1.2 christos if ( infile != NULL ) { 191 1.2 christos if (( fp = fopen( infile, "r" )) == NULL ) { 192 1.2 christos perror( infile ); 193 1.2 christos retval = EXIT_FAILURE; 194 1.2 christos goto fail; 195 1.2 christos } 196 1.2 christos } else { 197 1.2 christos fp = stdin; 198 1.1 lukem } 199 1.1 lukem 200 1.1 lukem ld = tool_conn_setup( 0, 0 ); 201 1.1 lukem 202 1.1 lukem tool_bind( ld ); 203 1.1 lukem 204 1.1 lukem tool_server_controls( ld, NULL, 0 ); 205 1.1 lukem 206 1.2 christos retval = rc = 0; 207 1.2 christos if (havedn) 208 1.2 christos retval = domodrdn( ld, entrydn, rdn, newSuperior, remove_old_RDN ); 209 1.2 christos else while ((rc == 0 || contoper) && fgets(buf, sizeof(buf), fp) != NULL) { 210 1.2 christos if ( *buf != '\n' ) { /* blank lines optional, skip */ 211 1.2 christos buf[ strlen( buf ) - 1 ] = '\0'; /* remove nl */ 212 1.2 christos 213 1.2 christos if ( havedn ) { /* have DN, get RDN */ 214 1.2 christos if (( rdn = strdup( buf )) == NULL ) { 215 1.2 christos perror( "strdup" ); 216 1.2 christos retval = EXIT_FAILURE; 217 1.2 christos goto fail; 218 1.2 christos } 219 1.2 christos rc = domodrdn(ld, entrydn, rdn, newSuperior, remove_old_RDN ); 220 1.2 christos if ( rc != 0 ) 221 1.2 christos retval = rc; 222 1.2 christos havedn = 0; 223 1.2 christos free( rdn ); rdn = NULL; 224 1.2 christos free( entrydn ); entrydn = NULL; 225 1.2 christos } else if ( !havedn ) { /* don't have DN yet */ 226 1.2 christos if (( entrydn = strdup( buf )) == NULL ) { 227 1.2 christos retval = EXIT_FAILURE; 228 1.2 christos goto fail; 229 1.2 christos } 230 1.2 christos ++havedn; 231 1.2 christos } 232 1.2 christos } 233 1.1 lukem } 234 1.1 lukem 235 1.2 christos fail: 236 1.2 christos if ( fp && fp != stdin ) fclose( fp ); 237 1.2 christos if ( entrydn ) free( entrydn ); 238 1.2 christos if ( rdn ) free( rdn ); 239 1.2 christos tool_exit( ld, retval ); 240 1.1 lukem } 241 1.1 lukem 242 1.1 lukem static int domodrdn( 243 1.2 christos LDAP *ld, 244 1.2 christos char *dn, 245 1.2 christos char *rdn, 246 1.2 christos char *newSuperior, 247 1.2 christos int remove ) /* flag: remove old RDN */ 248 1.1 lukem { 249 1.1 lukem int rc, code, id; 250 1.1 lukem char *matcheddn=NULL, *text=NULL, **refs=NULL; 251 1.1 lukem LDAPControl **ctrls = NULL; 252 1.1 lukem LDAPMessage *res; 253 1.1 lukem 254 1.2 christos if ( verbose ) { 255 1.1 lukem printf( _("Renaming \"%s\"\n"), dn ); 256 1.1 lukem printf( _("\tnew rdn=\"%s\" (%s old rdn)\n"), 257 1.1 lukem rdn, remove ? _("delete") : _("keep") ); 258 1.1 lukem if( newSuperior != NULL ) { 259 1.1 lukem printf(_("\tnew parent=\"%s\"\n"), newSuperior); 260 1.1 lukem } 261 1.1 lukem } 262 1.1 lukem 263 1.1 lukem if( dont ) return LDAP_SUCCESS; 264 1.1 lukem 265 1.1 lukem rc = ldap_rename( ld, dn, rdn, newSuperior, remove, 266 1.1 lukem NULL, NULL, &id ); 267 1.1 lukem 268 1.1 lukem if ( rc != LDAP_SUCCESS ) { 269 1.1 lukem fprintf( stderr, "%s: ldap_rename: %s (%d)\n", 270 1.1 lukem prog, ldap_err2string( rc ), rc ); 271 1.1 lukem return rc; 272 1.1 lukem } 273 1.1 lukem 274 1.1 lukem for ( ; ; ) { 275 1.1 lukem struct timeval tv = { 0, 0 }; 276 1.1 lukem 277 1.1 lukem if ( tool_check_abandon( ld, id ) ) { 278 1.1 lukem return LDAP_CANCELLED; 279 1.1 lukem } 280 1.1 lukem 281 1.1 lukem tv.tv_sec = 0; 282 1.1 lukem tv.tv_usec = 100000; 283 1.1 lukem 284 1.1 lukem rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res ); 285 1.1 lukem if ( rc < 0 ) { 286 1.1 lukem tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL ); 287 1.1 lukem return rc; 288 1.1 lukem } 289 1.1 lukem 290 1.1 lukem if ( rc != 0 ) { 291 1.1 lukem break; 292 1.1 lukem } 293 1.1 lukem } 294 1.1 lukem 295 1.1 lukem rc = ldap_parse_result( ld, res, &code, &matcheddn, &text, &refs, &ctrls, 1 ); 296 1.1 lukem 297 1.1 lukem if( rc != LDAP_SUCCESS ) { 298 1.1 lukem fprintf( stderr, "%s: ldap_parse_result: %s (%d)\n", 299 1.1 lukem prog, ldap_err2string( rc ), rc ); 300 1.1 lukem return rc; 301 1.1 lukem } 302 1.1 lukem 303 1.1 lukem if( verbose || code != LDAP_SUCCESS || 304 1.1 lukem (matcheddn && *matcheddn) || (text && *text) || (refs && *refs) ) 305 1.1 lukem { 306 1.1 lukem printf( _("Rename Result: %s (%d)\n"), 307 1.1 lukem ldap_err2string( code ), code ); 308 1.1 lukem 309 1.1 lukem if( text && *text ) { 310 1.1 lukem printf( _("Additional info: %s\n"), text ); 311 1.1 lukem } 312 1.1 lukem 313 1.1 lukem if( matcheddn && *matcheddn ) { 314 1.1 lukem printf( _("Matched DN: %s\n"), matcheddn ); 315 1.1 lukem } 316 1.1 lukem 317 1.1 lukem if( refs ) { 318 1.1 lukem int i; 319 1.1 lukem for( i=0; refs[i]; i++ ) { 320 1.1 lukem printf(_("Referral: %s\n"), refs[i] ); 321 1.1 lukem } 322 1.1 lukem } 323 1.1 lukem } 324 1.1 lukem 325 1.1 lukem if (ctrls) { 326 1.1 lukem tool_print_ctrls( ld, ctrls ); 327 1.1 lukem ldap_controls_free( ctrls ); 328 1.2 christos } 329 1.1 lukem 330 1.1 lukem ber_memfree( text ); 331 1.1 lukem ber_memfree( matcheddn ); 332 1.1 lukem ber_memvfree( (void **) refs ); 333 1.1 lukem 334 1.1 lukem return code; 335 1.1 lukem } 336