diff --git a/servers/slapd/back-passwd/search.c b/servers/slapd/back-passwd/search.c index 98d9050426..dd6c5a8d1c 100644 --- a/servers/slapd/back-passwd/search.c +++ b/servers/slapd/back-passwd/search.c @@ -321,7 +321,7 @@ pw2entry( Backend *be, struct passwd *pw, Entry *e ) #ifdef HAVE_STRUCT_PASSWD_PW_GECOS /* - * if gecos is present, add it as a cn. first process it + * if gecos is present, add user's full name as a cn. first process it * according to standard BSD usage. If the processed cn has * a space, use the tail as the surname. */ @@ -332,22 +332,39 @@ pw2entry( Backend *be, struct passwd *pw, Entry *e ) ber_str2bv( pw->pw_gecos, 0, 0, &val ); attr_merge_normalize_one( e, ad_desc, &val, NULL ); - s = ber_bvchr( &val, ',' ); - if ( s ) *s = '\0'; - - s = ber_bvchr( &val, '&' ); + s = strchr( val.bv_val, (unsigned char)',' ); if ( s ) { - if( val.bv_len + pwlen < sizeof(buf) ) { - int i = s - val.bv_val; - strncpy( buf, val.bv_val, i ); - s = buf + i; - strcpy( s, pw->pw_name ); - *s = TOUPPER((unsigned char)*s); - strcat( s, val.bv_val + i + 1 ); - val.bv_val = buf; - } + *s = '\0'; + val.bv_len = s - val.bv_val; } - val.bv_len = strlen( val.bv_val ); + + s = strchr( val.bv_val, (unsigned char)'&' ); + if ( s ) { + unsigned r = sizeof buf; + /* if name with expanded `&` fits in buf */ + if ( val.bv_len + pwlen <= r ) { + char * d = buf; + + for (;;) { + size_t const i = s - val.bv_val; + memcpy( d, val.bv_val, i ); + d += i; + memcpy( d, pw->pw_name, pwlen ); + *d = TOUPPER((unsigned char)*pw->pw_name); + d += pwlen; + r -= pwlen + i; + val.bv_len -= i + 1; + val.bv_val = s + 1; + + s = strchr( val.bv_val, (unsigned char)'&' ); + if (!(s && ( val.bv_len + pwlen <= r ))) + break; + } + strcpy( d, val.bv_val ); + val.bv_len = d - buf + val.bv_len; + val.bv_val = buf; + } // 1st fits + } // 1st & if ( val.bv_len && strcasecmp( val.bv_val, pw->pw_name ) ) { attr_merge_normalize_one( e, slap_schema.si_ad_cn, &val, NULL );